﻿/**
 * Created by no1 on 2014/9/1.
 */
'use strict';
var session = require('koa-generic-session');
// 通用 function
var fs = require('fs');
var path = require('path');
var md5 = require('md5');
var request = require('koa-request');
var async_request = require('request');
var C = require('../config');
var mysql = require('./mysql.js');
var MUsers = require('../model/users.js');
var MPosts = require('../model/posts.js');
var redis = require('redis');
var thunkify = require('thunkify');
var UPYUN = require('upyun-core');
var upyun = new UPYUN(C.upyun.bucket, C.upyun.user, C.upyun.pass);
var mActivity = require('../model/mActivity');
var mActivityStep = require('../model/mActivityStep');
var o2oF = require('../common/o2ofunction');
var imgRule =require('./imgRule')
var _s = require('underscore.string');
var _o2oServiceApi = require('../common/o2oServiceApi');
var o2oServiceApi = new _o2oServiceApi;

var nodemailer = require('nodemailer');
var commPost = require('../common/post');
var _C = {}; // MySQL 配置方式
_C.levelInfo = []; // 用户等级信息
_C.cityInfo = []; // 城市信息, 内部对象命名方式为: citycode_020: {citycode: 020,cityname: 广州}
_C.vests = [];// 马甲列表(除去官方账号等)，含:nicename,uid，如果缓存不存在,则从数据库中生成
_C.vests_id = [];// 马甲列表(全)，纯uid数组。如果缓存不存在,则从数据库中生成
_C.talentInfo = []; // 达人等级列表, 内部对象命名方式为: talent_1: {talentid: 1, name: 美容达人}
_C.talent_id = []; // 达人等级id的数组
_C.sliderInfo = {}; // 模块管理信息，内部对象命名方式 : sid_1:{xxxxx}
_C.brondSet = new Set(); // 模块管理信息，内部对象命名方式 : sid_1:{xxxxx}
//var smtpTransport = require('nodemailer-smtp-transport');

// create reusable transporter object using SMTP transport
var transporter = nodemailer.createTransport({
    host: C.email.smtp,
    port: 25,
    auth: {
        user: C.email.username,
        pass: C.email.password
    }
});
//var sleep = require('es6-sleep');
var mongo = require('../common/mongo_db');
//exports.ynDB = exports.mongo.ynDB;
exports.userModel = mongo.user;
exports.poiModel = mongo.poi;
mongo.initDB();
//exports.mongoose = exports.mongo.mongoose;

require('redis-lua2').attachLua(redis);
runOnce(redis);
var redisClient;
if (C.redis.unix_socket) { // Unix Socket 方式
    redisClient = redis.createClient(C.redis.unix_socket, C.redis.options);
} else { // TCP 方式
    redisClient = redis.createClient(C.redis.port, C.redis.host, C.redis.options);
}

var redisClientDb1; // db1
if (C.redis.unix_socket) { // Unix Socket 方式
    redisClientDb1 = redis.createClient(C.redis.unix_socket, C.redis.options);
} else { // TCP 方式
    redisClientDb1 = redis.createClient(C.redis.port, C.redis.host, C.redis.options);
}
redisClientDb1.select(1, function() {});

var wrapper = require('co-redis');
var redisCo = wrapper(redisClient);

var _ = require('underscore');

//加载词语过滤客户端
var scFilter = require('sc-filter').createClient();

if (C.wordFilter.unix_socket) { // Unix Socket 方式
    scFilter.connect(C.wordFilter.unix_socket);
} else { // TCP 方式
    scFilter.connect(C.wordFilter.port, 'localhost');
}

/**
 * @todo 过滤关键字
 * @param str
 * @returns {Function}
 */
function scMatch(str) {
    return function (cb) {
        scFilter.match(str, function (result) {
            cb(null, result);
        });
    }
}

exports.scMatch = scMatch;
exports.upyun = upyun;
//exports.sleep=sleep;
_.str = require('underscore.string');
_.v = require('validator');

Date.prototype.format = function (format) //author: meizz
{
    var o = {
        "M+": this.getMonth() + 1, //month
        "d+": this.getDate(),    //day
        "h+": this.getHours(),   //hour
        "m+": this.getMinutes(), //minute
        "s+": this.getSeconds(), //second
        "q+": Math.floor((this.getMonth() + 3) / 3),  //quarter
        "S": this.getMilliseconds() //millisecond
    };
    if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
        (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o)if (new RegExp("(" + k + ")").test(format))
        format = format.replace(RegExp.$1,
            RegExp.$1.length == 1 ? o[k] :
                ("00" + o[k]).substr(("" + o[k]).length));
    return format;
};

Date.prototype.addDays = function (d) {
    this.setDate(this.getDate() + d);
};


// 获取某天的起始时间戳 默认为当天 单位秒
exports.beginTimestamp = function (time1) {
    time1 = time1 == undefined ? timestamp() : parseInt(time1);
    var newDate = new Date(time1 * 1000);
    return parseInt(new Date(newDate.format('yyyy-MM-dd') + ' 0:0:0 CST+800').getTime() / 1000);
};

// 计算日期间隔 单位秒,time1 比 time2 晚时为负数
exports.dateDiff = function (time1, time2) {
    time1 = this.beginTimestamp(time1); // 计算某天的起始时间戳
    time2 = this.beginTimestamp(time2); // 计算某天的起始时间戳
    return parseInt((time2 - time1) / (60 * 60 * 24));
};

// 初始化 redis lua 加载
function runOnce(redis) {
    var luapath = path.resolve(__dirname, '../lua') + '/';
    var dirs = fs.readdirSync(luapath);
    var i;
    var common = fs.readFileSync(luapath + 'common.lua', 'utf-8');
    var source, fnName;
    for (i in dirs) {
        if (dirs[i].substr(-4, 4) === '.lua' && dirs[i] !== 'common.lua') {
            source = fs.readFileSync(luapath + dirs[i], 'utf-8');
            fnName = dirs[i].replace('.lua', '');
            console.log("Lua Script: %s", fnName);
            redis.lua(fnName, common + "\n" + source);
        }
    }
}


/*
 @todo 取得到秒的时间戳
 函数名：timestamp
 * 参数：无
 * 返回：当前时间的10位UNIX时间戳
 */
function timestamp() {
    return parseInt(new Date().getTime() / 1000);
}

exports.timestamp = timestamp;
//var initEnv={};
exports.redisCo = redisCo;
exports.redisClient = redisClient;
exports.redisClientDb1 = redisClientDb1;
//exports.luashas=lua.__shas;


//递归解析 I.cmd
function getCmd(I) {
    let cmd = isJson(I.cmd);
    delete I.cmd;
    if (cmd !== false) {
        for (var i in cmd) {
            if (typeof cmd[i] != "function") {
                I[i] = cmd[i];
            }
        }
    }
    if (!_.isEmpty(I.cmd)) {
        return getCmd(I);
    }
    return I;
}

// 是否广告、微商、手机或QQ号码、辱骂等垃圾信息
exports.isSPAM = function*(str){
    let tmp = str;
    let SPAM = 0;
    tmp = tmp.replace(/[oO①②③④⑤⑥⑦⑧⑨⑩〇一二三四五六七八九十零壹贰叁肆伍陆柒捌玖拾]/g, "1");
    if (tmp.replace(/(\d+)\D{1,8}/g,"$1").match(/\d{7,}/)) {
        SPAM = 1;
    }else{
        let checkWord = yield scMatch(tmp);
        if (checkWord.length > 0) {
            SPAM = 1;
        }
    }
    return SPAM;
};


exports.Init = function*(Env, actArray, I) {
    //var I = {};
    // {request.body.fields:{},params:{},query:{}}
    var _isSPAM = 0; // 是否垃圾、广告、微商、手机或QQ号码

    if (_.isEmpty(I)) {
        I = {};
        var fields = {};
        if (Env.request.body) {
            fields = Env.request.body.fields;
        }

        if (fields) {
            for (var field in fields) {
                I[field] = fields[field];
            }
        }
        var params = Env.params;
        if (params) {
            for (var parm in params) {
                I[parm] = params[parm];
            }

            if (I['apiVer']) {
                var pattern = /^v(\d+)$/gi;
                var tmpVer = pattern.exec(I['apiVer']);
                if (tmpVer[1] == undefined) {
                    I['apiVerNum'] = 1;
                } else {
                    I['apiVerNum'] = tmpVer[1];
                }
            } else {
                I['apiVerNum'] = 1;
            }
        }
        var querys = Env.query;
        if (querys) {
            for (var query in querys) {
              if(query !=='')
                I[query] = querys[query];
            }
        }
    }


    // 递归 cmd 参数
    I = getCmd(I);

    //if (I.cmd!=undefined){
    //  let cmd = isJson(I.cmd);
    //  delete I.cmd;
    //  if (cmd !== false){
    //    for (var i in cmd){
    //      if (typeof cmd[i] !="function"){
    //        I[i]=cmd[i];
    //      }
    //    }
    //  }
    //}
    //
    //if (I.cmd!=undefined){
    //  let cmd = isJson(I.cmd);
    //  if (cmd !== false){
    //    I = yield exports.Init(Env,actArray,I);
    //    return I;
    //  }
    //}


    var errors = {};
    if (I) {
        for (var i in I) {

            // act 参数存在,并且判断是大于0不超过2位的整数。
            if (_.v.isIn(i, ['act'])) {
                if (_.v.isInt(I[i])) {
                    if (I[i] >= 99 || I[i] < 1) {
                        errors.param = i;
                        errors.msg = i + ' 参数超出取值范围';
                        errors.level = 3;
                        break;
                    }
                    if (!_.v.isIn(I[i], actArray)) {
                        errors.param = i;
                        errors.msg = '未定义的功能';
                        errors.level = 3;
                        break;
                    }
                } else {
                    errors.param = i;
                    errors.level = 3;
                    errors.msg = i + ' 参数必须是整数';
                    break;
                }
            }

            // uid,tid,pid,tagid 参数存在,并且判断是大于0不超过10位的整数。
            if (_.v.isIn(i, ['uid', 'tid', 'pid', 'tagid', 'page', 'pagesize'])) {
                if (_.v.isInt(I[i])) {
                    I[i] = parseInt(I[i]);
                    if (I[i] >= Math.pow(10, 11) || I[i] < 1) {
                        errors.param = i;
                        errors.level = 3;
                        errors.msg = i + ' 参数超出取值范围';
                        break;
                    }
                } else {
                    errors.param = i;
                    errors.msg = i + ' 参数必须是整数';
                    break;
                }
            }

            // pagesize 参数存在,并且判断是大于0不超过50的整数。
            if (_.v.isIn(i, ['pagesize'])) {
                if (_.v.isInt(I[i])) {
                    if (I[i] > 50 || I[i] < 1) {
                        errors.param = i;
                        errors.level = 3;
                        errors.msg = i + ' 参数超出取值范围';
                        break;
                    }
                } else {
                    errors.param = i;
                    errors.msg = i + ' 参数必须是整数';
                    break;
                }
            }

            // mobile 参数存在,并且判断是否符合手机号码。
            if (_.v.isIn(i, ['mobile'])) {
                if (_.v.isInt(I[i])) {
                    if (I[i] > 19999999999 || I[i] < 13000000000) {
                        errors.param = i;
                        errors.level = 1;
                        errors.msg = '手机号码格式不对';
                        break;
                    }
                } else {
                    errors.param = i;
                    errors.level = 1;
                    errors.msg = '手机号码格式不对';
                    break;
                }
            }

            // password,ticket 参数存在,并且判断是否32位。
            if (_.v.isIn(i, ['password', 'ticket', 'oldpwd', 'newpwd'])) {
                if (_.v.isAlphanumeric(I[i])) {
                    if (!_.v.isByteLength(I[i], 32, 32)) {
                        errors.param = i;
                        errors.level = 3;
                        errors.msg = i + ' 参数必须是MD5(32)格式';
                        break;
                    } else if (I[i] == 'd41d8cd98f00b204e9800998ecf8427e') {
                        errors.param = i;
                        errors.level = 1;
                        errors.msg = i + ' 参数不能为空';
                    }
                    if (i == 'password' || i == 'oldpwd' || i == 'newpwd') {
                        I[i] = I[i].toLowerCase();
                    }
                } else {
                    errors.param = i;
                    errors.level = 3;
                    errors.msg = i + ' 参数必须是数字或字母';
                    break;
                }
            }

            // tokenkey 参数存在,并且判断是否40位。
            if (_.v.isIn(i, ['tokenkey'])) {
                if (I[i] == "") {
                    I[i] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
                } else {
                    if (_.v.isAlphanumeric(I[i])) {
                        if (!_.v.isByteLength(I[i], 40, 40)) {
                            errors.param = i;
                            errors.level = 3;
                            errors.msg = i + ' 参数必须是40位格式';
                            break;
                        }
                    } else {
                        errors.param = i;
                        errors.level = 3;
                        errors.msg = i + ' 参数必须是数字或字母';
                        break;
                    }
                }
            }

            // 敏感词汇过滤
            //if (_.v.isIn(i, ['post', 'nickname', 'signature', 'tagtitle', 'tags', 'tagdesc', 'title'])) {
            if (_.v.isIn(i, ['post', 'nickname', 'signature', 'tagtitle', 'tags', 'tagdesc'])) {
                if (i == 'tags' && isJson(I[i])) {
                    let tmp_tags = isJson(I[i]);
                    for (var j in tmp_tags) {
                        if (tmp_tags[j]['tagstitle']) {
                            let tmp = tmp_tags[j]['tagstitle'];
                            let SPAM = yield exports.isSPAM(tmp);
                            if (SPAM == 1){
                                errors.param = i;
                                errors.level = 1;
                                errors.msg = '不能含有QQ、微信、手机、敏感词汇，请修改后再次提交';
                                break;
                            }

                          //  tmp = tmp.replace(/[oO①②③④⑤⑥⑦⑧⑨⑩〇一二三四五六七八九十零壹贰叁肆伍陆柒捌玖拾]/g, "1");
                          //if (tmp.replace(/(\d+)\D{1,8}/g,"$1").match(/\d{7,}/)) {
                          //      errors.param = i;
                          //      errors.level = 1;
                          //      errors.msg = '不能含有QQ、微信、手机号码，请修改后再次提交';
                          //      break;
                          //  }
                          //
                          //  let checkWord = yield scMatch(tmp_tags[j]['tagstitle']);
                          //  if (checkWord.length > 0) {
                          //      errors.param = i;
                          //      errors.level = 1;
                          //      errors.msg = '含有争议或敏感词汇[' + checkWord[0][1] + ']，请修改后再次提交';
                          //      break;
                          //  }
                        }
                    }
                } else {
                    //let SPAM = yield scMatch(I[i]);
                    let SPAM = yield exports.isSPAM(I[i]);
                    _isSPAM=SPAM;
                    if (SPAM == 1) {
                        if (i == 'post') {
                            I[i] = I[i].replace(/\[cp\].*\[\/cp\]/, "");
                            I[i] = I[i].replace(/\[em\].*\[\/em\]/, "");
                        }else{
                            errors.param = i;
                            errors.level = 1;
                            errors.msg = '不能含有QQ、微信、手机、敏感词汇，请修改后再次提交';
                            break;
                        }
                    }

                    //let checkWord = yield scMatch(I[i]);
                    //if (checkWord.length > 0) {
                    //    errors.param = i;
                    //    errors.level = 1;
                    //    errors.msg = '含有争议或敏感词汇[' + checkWord[0][1] + ']，请修改后再次提交';
                    //    break;
                    //}

                    //   let tmp = I[i];
                    //    tmp = tmp.replace(/[oO①②③④⑤⑥⑦⑧⑨⑩〇一二三四五六七八九十零壹贰叁肆伍陆柒捌玖拾]/g, "1");
                    //  if (tmp.replace(/(\d+)\D{1,8}/g,"$1").match(/\d{7,}/)) {
                    //        errors.param = i;
                    //        errors.level = 1;
                    //        errors.msg = '不能含有QQ、微信、手机号码，请修改后再次提交';
                    //    }
                    //}
                }
            }

            // nickname 参数存在,并且判断是不大于10位。
            if (_.v.isIn(i, ['nickname'])) {
                I[i] = _.str.trim(I[i]); //去除收尾空字符,移除HTML标签 .stripTags()
                I[i] = I[i].replace(/\n+|\'|\"/mg, ''); //去除换行符、单引号、双引号
                I[i] = I[i].replace(/\s+/mg, ' '); //多个空格合并为1个空格
                if (!_.v.isLength(I[i], 2, 10)) {
                    errors.param = i;
                    errors.level = 1;
                    errors.msg = '昵称必须在2-10个字符以内';
                    break;
                }
            }

            // title 参数存在,并且判断是不大于30位。 美容日记，友盟推送
            //if (_.v.isIn(i, ['title'])) {
            //    I[i] = _.str.trim(I[i]); //去除收尾空字符,移除HTML标签 .stripTags()
            //    if (!_.v.isLength(I[i], 2, 30)) {
            //        errors.param = i;
            //        errors.level = 1;
            //        errors.msg = '标题必须在2-30个字符以内';
            //        break;
            //    }
            //}

            // signature 参数存在,并且判断是不大于30位。
            if (_.v.isIn(i, ['signature'])) {
                I[i] = _.str.trim(I[i]); //去除收尾空字符,移除HTML标签 .stripTags()
                if (!_.v.isLength(I[i], 0, 30)) {
                    errors.param = i;
                    errors.level = 1;
                    errors.msg = '签名必须在30个字符以内';
                    break;
                }
            }

            // post 参数存在,并且判断是不大于250位。
            if (_.v.isIn(i, ['post'])) {
                I[i] = _.str.trim(I[i]); //去除收尾空字符
//        if (!_.v.isLength(I[i], 0,250)) {
//          errors.param = i;
//          errors.level = 1;
//          errors.msg = '签名必须在250个字符以内';
//          break;
//        }
//        else{
                I[i] = _.str.escapeHTML(I[i]); // HTML标签类转义
//        }
            }

            // tagtitle 参数存在,并且判断是1-10位。
            if (_.v.isIn(i, ['tagtitle'])) {
                I[i] = _.str.trim(I[i]); //去除收尾空字符,移除HTML标签 .stripTags()
                if (!_.v.isLength(I[i], 1, 30)) {
                    errors.param = i;
                    errors.level = 1;
                    errors.msg = '标签名称必须在1-30个字符以内';
                    break;
                }
            }

            // 判断日期格式是否正常
            if (_.v.isIn(i, ['sDate', 'eDate'])) {
                I[i] = _.str.trim(I[i]); //去除收尾空字符,移除HTML标签 .stripTags()
                if (!_.v.isDate(I[i])) {
                    errors.param = i;
                    errors.level = 1;
                    errors.msg = '日期格式错误';
                    break;
                }
            }

            // 去掉首尾空格
            if (_.v.isIn(i, ['tagtitle', 'nickname', 'post'])) {
                I[i] = _.str.trim(I[i]);
            }
        }

        if (_isSPAM!=0){
            I['_isSPAM'] = _isSPAM;
        }
        I.head_mark={};
        let head_mark = Env.request.accept.headers['mark']||'';
        let pattern = /[a-z,A-Z]{1,3}/mg;
        let markArr=head_mark.split(':');
        if(head_mark==undefined||markArr.length==0){
            I.head_mark.mark='';
        }else{
            I.head_mark.mark=head_mark;
        }
        let objMark={};
        for(let item of markArr){
            let arr=item.match(pattern);
            if (arr) {
                let key=arr[0];
                let value=item.replace(arr[0],'');
                if(_.v.isInt(value)){
                    value=parseInt(value);
                }else{value=0;}
                objMark[key]=value;
            }
        }
        I.head_mark.decodemark=objMark;
    var didInfo = {
      type: 0,
      device_id: ''
    };
    var did = Env.request.accept.headers['did'] || '';
    did = did.toLocaleLowerCase();
    if (did && did.length == 35) {
      let did_arr = did.split("-");
      try {
        didInfo.type = parseInt(did_arr[0]);
        didInfo.device_id = did_arr[1].toLowerCase();
      }
      catch (err) {
        console.log(err);
      }
    }
    I.device_id = didInfo;
        var app_ver = Env.request.accept.headers['app-ver'];
        var appInfo = {
            os: 0, // 0 未知系统, 1 Android, 2 IOS
            code: 0, // 版本 code 号
            ver: '',// 版本号
            test: 0, // 0 正式版本, 1 测试版本
            channel: ''
        };

        I.app_ver_arr = appInfo;

        if (app_ver == undefined) {
            app_ver = '';
        } else { // a-22-2.1.8a-Xiaomi
            let app_ver_arr = app_ver.split("-");
            try {
                // 判断 os
                if (app_ver_arr[0] == 'a') {
                    appInfo.os = 1;
                } else if (app_ver_arr[0] == 'i') {
                    appInfo.os = 2;
                }

                // 判断 code
                if (_.v.isNumeric(app_ver_arr[1])) {
                    appInfo.code = parseInt(app_ver_arr[1]);
                }

                // 判断 ver test
                if (app_ver_arr[2]) {
                    appInfo.ver = app_ver_arr[2];
                    appInfo.test = _.v.isNumeric(app_ver_arr[2].slice(-1)) ? 1 : 0;
                }

                appInfo.channel = app_ver_arr[3];
                I.app_ver_arr = appInfo;
            }
            catch (err) {
                //在这里处理错误
                console.log(err);
            }
        }

        if (I.tokenkey && I.tokenkey.length==40){
            if(Env.foro2o && Env.foro2o==true){
                console.log('call from o2o');
                I['loginStatus'] = yield o2oF.o2oIsLogin({I:I,ip:Env.ip});
            }else{
                I['loginStatus'] = yield exports.isLogin({I:I,ip:Env.ip});
            }
        }else{
            I['loginStatus'] = {
                status: false
            };
        }


        if (!_.isEmpty(errors)) {
            I.errors = errors;
            console.log('[ERR] [%s] [%s] [%s] <%s> [%s] [%s] [%s] <%s>', new Date().format('yyyy-MM-dd hh:mm:ss'), Env.ip, app_ver, did,
                Env.request.method, Env.req.url, errors, Env.request.accept.headers['user-agent']);
        }

        console.log('[INFO] [%s] [%s] [%s] <%s> [%s] [%s] <%s>', new Date().format('yyyy-MM-dd hh:mm:ss'), Env.ip, app_ver, did,
            Env.request.method, Env.req.url, Env.request.accept.headers['user-agent']);
        if (C.env != 'production') {
            console.log('[Input] [%O]', I);
        }
    }

    return I;
};

/*
 @todo 判断是否管理员
 函数名：isManager()
 * 参数: groupid
 * 返回: true/false
 */

exports.isManager = function (groupid, groupArray) {
    if (_.isArray(groupArray)) {
        groupArray = _.intersection(groupArray, [1, 2, 3]);
    } else {
        groupArray = [1, 2, 3];
    }
    return _.v.isIn(groupid, groupArray);
};

/*
 @todo 取得到秒的时间戳
 函数名：timestamp
 * 参数：无
 * 返回：当前时间的10位UNIX时间戳
 */
exports.timestamp = timestamp;
/*
 @todo 获取用户ip地址对应的城市信息
 1.如果ip存在于表，并且没过期（暂定最后更新日期在一年内），则返回ip对应的region跟city信息；若已经过期，则到淘宝查询对应ip地址所在城市信息
 2.如果该ip不存在于本地SQL数据库里面，则到淘宝API查询对应的城市信息，并插入，返回城市信息
 函数名：getUserCity
 * 参数：无
 * 返回：{region:a,citycode:b}
 */
exports.getUserCityData=function*(ip){
    let ip_valid=false;
    let ip_exist=false;
    let return_data={};

    // 通过IP获取所在地
    let ip_start = ip.lastIndexOf(':');
    ip = ip.slice(ip_start >= 0 ? ip_start + 1 : 0);
    if (ip.slice(0, 8) == '192.168.'||ip=='::1'||ip=='1') {
        return_data.is_local = true;
        return_data.city_id = '0';
        return_data.city = 'local';
        return return_data;
    }

    let ip_info=yield mysql.query('SELECT city_id,city,timestampdiff(year,FROM_UNIXTIME(timeline, \'%Y-%m-%d\'),FROM_UNIXTIME(unix_timestamp(now()), \'%Y-%m-%d\')) duration from mh_ip_info where ip=? order by ipid desc limit 0,1',[ip]);
    if (ip_info && ip_info.length > 0) {
        if (ip_info && parseInt(ip_info[0].duration) == 0) {
            ip_valid = true;
            return_data.city_id = ip_info[0].city_id;
            return_data.city = ip_info[0].city;
            return return_data;
        }else{
            ip_exist = true;
        }
    }
    if(!ip_valid) {//如果不存在该ip或该ip已过期
        let options = {
            url: 'http://ip.taobao.com/service/getIpInfo.php?ip=' + ip,
            headers: {'User-Agent': 'request'},
            method: 'GET',
            timeout: 50000
        };
        let home = yield request(options);
        let cityInfo = isJson(home.body);
        if (cityInfo.code == 0) { // 有效数据
            return_data.is_local = false;
            return_data.city_id = cityInfo.data.city_id;
            return_data.city = cityInfo.data.city;
            if (ip_exist) {//IP存在则更新，不存在更插入到数据库
                mysql.query('update mh_ip_info set country=?,area=?,city_id=?,city=?,region=?,timeline=UNIX_TIMESTAMP(),json_info=? where ip=?', [cityInfo.data.country,
                    cityInfo.data.area, cityInfo.data.city_id, cityInfo.data.city, cityInfo.data.region, JSON.stringify(cityInfo.data), ip]);
            } else {
                let sql = ' where not exists(SELECT 1 from mh_ip_info where ip =\'' + ip + '\')';
                yield mysql.query('INSERT INTO mh_ip_info(ip,country,area,city_id,city,region,timeline,json_info) select ?,?,?,?,?,?,UNIX_TIMESTAMP(),? from dual ' + sql,
                  [ip, cityInfo.data.country, cityInfo.data.area, cityInfo.data.city_id, cityInfo.data.city, cityInfo.data.region, JSON.stringify(cityInfo.data)]);
            }
        }
    }
    return return_data;
};


/*
 @todo 判断当前用户是否已登录
 函数名：isLogin
 * 参数：无
 * 返回：true,false
 */
exports.isLogin = function*(Env) {
    var fields = Env.I;
    let ip = Env.ip || '';//客户端ip
    console.log(Env.ip);
    var act = fields.act;
    var returnData = {
        status: false
    };
    //if(act<21){//app端
    var tokenKey = fields.tokenkey || '';
    if (tokenKey.length == 40) {
        var uid = yield redisCo.get('siss:user:token_' + tokenKey);
        if (uid != null && parseInt(uid) > 0) { // 如果已经在redis中存在
            var userInfo = yield redisCo.hmget('siss:user:uid_' + uid, ['uid', 'groupid', 'nickname', 'vestuid', 'vestnickname','city','city_id']);
            if (userInfo[0] == null || userInfo[1] == 5) {
                return returnData;
            }
            if (userInfo[5] == null || userInfo[6] == null) {
                if(ip.length>0){
                    let regionData = yield this.getUserCityData(ip);
                    returnData.city = regionData.city;
                    returnData.city_id = regionData.city_id;
                    redisClient.hmset('siss:user:uid_' + userInfo[0],'city',regionData.city,'city_id',regionData.city_id
                    );
                    redisClient.expire('siss:user:uid_' + userInfo[0], C.session.ttl);
                }
            }else{
                returnData.city=userInfo[5];
                returnData.city_id=userInfo[6];
            }
            returnData.status = true;
            returnData.uid = parseInt(userInfo[0]);
            returnData.groupid = parseInt(userInfo[1]);
            returnData.nickname = userInfo[2];
            if (this.isManager(returnData.groupid)) { // 判断是否管理组成员
                returnData.vestuid = parseInt(userInfo[3]);
                returnData.vestnickname = userInfo[4];
            }
            redisClient.expire('siss:user:token_' + tokenKey, C.session.ttl);
            redisClient.expire('siss:user:uid_' + userInfo[0], C.session.ttl);
        } else { //在redis中不存在
            var tokenKeyExp = parseInt(C.user.tokenKeyExp);//单位天
            var tokenKeyExp = tokenKeyExp * 24 * 60 * 60;
            var userInfo = yield MUsers.getUser('uid,groupid,nickname', 'tokenkey=? AND tokenttl+ ' + tokenKeyExp + ' >UNIX_TIMESTAMP()', [tokenKey]);
            if (userInfo.length > 0 && userInfo[0].groupid != 5) { // gid=5 是禁止访问组

                let regionData={city:'',city_id:''};
                //获取用户所在城市
                if (ip.length > 0) {
                    regionData = yield this.getUserCityData(ip);
                    userInfo[0].city = regionData.city;
                    userInfo[0].city_id = regionData.city_id;
                }
                // 记录登录日志
                this.loginLog(userInfo[0].uid, 2, ip,regionData);


                redisClient.SETEX('siss:user:token_' + tokenKey, C.session.ttl, userInfo[0].uid);//保存会话
                if (this.isManager(userInfo[0].groupid)) { // 判断是否管理组成员
                    redisClient.hmset('siss:user:uid_' + userInfo[0].uid,
                        'uid', userInfo[0].uid,
                        'groupid', userInfo[0].groupid,
                        'nickname', userInfo[0].nickname,
                        'vestuid', userInfo[0].uid,
                        'vestnickname', userInfo[0].nickname,
                        'city',userInfo[0].city,
                        'city_id',userInfo[0].city_id
                    );
                } else {
                    redisClient.hmset('siss:user:uid_' + userInfo[0].uid, 'uid', userInfo[0].uid, 'groupid',
                        userInfo[0].groupid, 'nickname', userInfo[0].nickname,
                        'city',userInfo[0].city,'city_id',userInfo[0].city_id
                    );
                }

                redisClient.expire('siss:user:uid_' + userInfo[0].uid, C.session.ttl);
                returnData.status = true;
                returnData.uid = userInfo[0].uid;
                returnData.groupid = userInfo[0].groupid;
                returnData.nickname = userInfo[0].nickname;
                returnData.city=userInfo[0].city;
                returnData.city_id=userInfo[0].city_id;
                if (this.isManager(returnData.groupid)) { // 判断是否管理组成员
                    returnData.vestuid = userInfo[0].uid;
                    returnData.vestnickname = userInfo[0].nickname;
                }
            } else return returnData;
        }
    }

    //}else if(act>20){//pc端
    //  var session =Env.session;
    //  if(session.uid!=''&&parseInt(session.uid)>0){
    //    var userInfo=redisClient.hmget('siss:user:uid_'+session.uid,['uid','groupid','nickname','vestuid','vestnickname']);
    //    returnData.status=true;
    //    returnData.uid=userInfo[0];
    //    returnData.groupid=userInfo[1];
    //    returnData.nickname=userInfo[2];
    //    if (this.isManager(returnData.groupid)){ // 判断是否管理组成员
    //      returnData.vestuid=userInfo[3];
    //      returnData.vestnickname=userInfo[4];
    //    }
    //  }else{
    //    returnData.status=false;
    //  }
    //}
    return returnData;
};


/*
 @todo获取页面返回信息（返回对象）
 @status 状态码
 @msg  返回信息
 @level 返回信息等级
 @data 数据项（对象）
 */
exports.returnMsg = function (status, msg, level, data) {
    var returnData = {};
    returnData.status = status || 200;
    returnData.message = {
        msg: msg || "",
        level: level || 3,
        time: this.timestamp()
    };
    returnData.result = {};
    if (typeof data === "object" && data !== null) {
        returnData.result = data;
    }

    if (level == 4) { // 增加经验和悦币, msg 格式为: {e:-123,b:0,act:'点赞成功'}  【e:经验,b:悦币】
        returnData.message.msg = "";
        returnData.message.level = 3;
        if (typeof msg === "object") {
            var e = msg.e || 0;
            var b = msg.b || 0;
            if (e != 0 && b != 0) { //如果既传经验，也传悦币
                //格式: 经验 +10，悦币 +5
                returnData.message.msg = "经验 " + (e > 0 ? "+" : "") + e + "分，悦币 " + (b > 0 ? "+" : "");
            } else if (e != 0) { //只传经验
                //格式: 经验 +10
                returnData.message.msg = "经验 " + (e > 0 ? "+" : "") + e + "分";
            } else if (b != 0) {
                //格式: 悦币 +10
                returnData.message.msg = "悦币 " + (e > 0 ? "+" : "") + e;
            }

            // 插入动作
            if (returnData.message.msg != '' && msg.act != undefined) {
                //if (msg.act.sub(-2)!='成功'){
                //  msg.act=msg.act+'成功';
                //}

                returnData.message.msg = msg.act + ' ' + returnData.message.msg;
            }
            returnData.message.level = 4;
        }
    }

    if (C.env != 'production') {
        console.log('[RETURN] [%s] [%s]', returnData.status, returnData.message.msg);
    }
    return returnData;
};

/*
 @todo 验证是否是手机号码
 */
exports.isMobile = function (mob) {
    if (mob > 19999999999 || mob < 13000000000) {
        return false;
    } else {
        return true;
    }
};

/* 函数名：sendSMS
 * 参数：mob:手机号码,msg:UTF-8编码的短信内容
 * 返回：
 * 功能：发送短信
 */

exports.sendSMS = function* (mob, msg) {
    var options = {
        url: C.SMS.sms_url + '?sn=' + C.SMS.sms_sn + '&pwd=' + C.SMS.sms_pwd + '&mobile=' + mob + '&content=' + escape(msg + C.SMS.sms_footer) + '&ext=&stime=&rrid=' + C.SMS.sms_rrid,
        //url: C.SMS.sms_url+'?sn='+C.SMS.sms_sn+'&pwd='+C.SMS.sms_pwd+'&mobile='+mob+'&content='+msg+C.SMS.sms_footer+'&ext=&stime=&rrid='+C.SMS.sms_rrid,
        headers: {'User-Agent': 'request'}
    };
    var response = yield request(options); //Yay, HTTP requests with no callbacks!
    var retCode = response.body.match(/(\d{4,15})/mg);
    //retCode = retCode.match(/<string xmlns=\"http:\/\/tempuri.org\/\">(.*)<\/string>/mg);
    return (retCode == C.SMS.sms_rrid);
};

/*
 @todo 检测手机号码是否存在
 */
exports.existMobile = function*(mobile) {
    var flag = false;
    var userData = yield mysql.query("select uid from mh_user where mobile=?", [mobile]);
    if (userData.length > 0) {
        flag = true;
    }
    return flag;
};

/*
 @todo 根据用户手机号码查找用户
 */
exports.getUserByMobile = function*(mobile) {
    let userData = yield mysql.queryOne("select uid,nickname,groupid from mh_user where mobile=?", [mobile]);
    return userData;
};

/*
 @todo 获取随机数
 @len 随机数位数
 */
exports.getRandom = function (len) {
    return Math.floor(Math.random() * (Math.pow(10, len) - Math.pow(10, len - 1)) + Math.pow(10, len - 1));
};

/*
 * 根据face值生成头像图片URL
 *
 * @face 0-用户自定义头像，非0-默认随机头像
 * @uid 用户uid
 * @type type=1时头像大小为300*300,type=2时头像大小为600*600 默认75*75
 * */
exports.generateFaceUrl = function (face, uid, type) {
    var url = '';
    var avatarSuffix = C.upyun.avatar_suffix_default;
    if (type == 1) {
        avatarSuffix = C.upyun.avatar_suffix;
    } else if (type == 2) {
//    avatarSuffix=C.upyun.avatar_suffix_big;
    }
    if (face == 0) {  // 用户自定义头像
        uid = uid.toString();  // 12345
        var img = _.str.lpad(uid, 9, '0');
        var pos = [3, 6, 9];
        for (var i = 0; i < pos.length; i++) {
            img = _.str.insert(img, pos[i], '/');
        }
        url = C.upyun.avatar_url + '/' + img + avatarSuffix;
    } else {  // 默认随机头像
        url = C.upyun.default_avatar_url + '/' + face + avatarSuffix;
    }
    return url;
};

/*
 *todo 生成标签图地址
 * @tagimg 0-用户自定义标签图，非0-系统默认标签
 * @tagid 标签id
 * * @type 默认原图 1 小图（75*75）
 * */
exports.generateTagUrl = function (tagimg, tagid, type) {
    var url = '';
    var tagSuffix = '.jpg';
    if (type == 1) {
        tagSuffix = C.upyun.tag_suffix_min;
    } else if (type == 2) {
        tagSuffix = C.upyun.tag_suffix_middle;
    }
    if (tagimg == 0) {  // 用户自定义标签图
        tagid = tagid.toString();  // 12345
        var img = _.str.lpad(tagid, 9, '0');//tagid不足9位时左边补0
        var pos = [3, 6, 9];
        for (var i = 0; i < pos.length; i++) {
            img = _.str.insert(img, pos[i], '/');
        }
        url = C.upyun.tag_url + '/' + img + tagSuffix;
    } else {  // 系统默认标签图
        url = C.upyun.default_tag_url + '/' + tagimg + tagSuffix;
    }
    return url;
};


exports.generateVideoURL = function (videoKeyName) {
    return C.upyun.video_url + '/' + videoKeyName + '.mp4';
}
/*
 * @todo 生成贴子图地址
 * @pid 贴子id
 * @imgext 图片扩展名
 * * @type 默认大图 1为小图(75*75);不需要加后缀.v=2为视频截图
 * @imgIndex  图索引
 * */
exports.generateAttachmentUrl = function (pid, imgext, type, imgIndex) {
    var url = "";
    var suffix = C.upyun.suffix;
    if (type == 1) {
        suffix = C.upyun.suffix_min;
    }
    else if (type == 2) {
        if (imgext == 'screenshot') {
            suffix = C.upyun.video_screenshot_suffix;
        } else if (imgext == 'play') {
            suffix = C.upyun.video_play_suffix;
        }
    }

    if (pid > 0 && (imgext != '' || type == 2)) {
        pid = pid.toString();
        var img = _.str.lpad(pid, 10, '0');//pid不足10位时左边补0
        var str = '';
        if (imgIndex != undefined) {
            if (type != 2) {
                imgIndex = parseInt(imgIndex);
            }
            if (imgIndex > 0 || type == 2) {
                str += '-' + imgIndex;
                if (type == 2) {
                    imgext = 'jpg';
                }
            }
        }
        img = img.substring(0, 3) + '/' + img.substring(3, 5) + '/' + img.substring(5, 7) + '/' + img.substring(7) + str;
        url = C.upyun.img_url + '/' + img + '.' + imgext + suffix;
    }
    return url;
};
/*
 * @todo 生成轮播图地址
 * @aid 贴子aid
 * */
exports.generateSliderUrl = function (aid) {
    var url = "";
    if (aid > 0) {
        aid = aid.toString();
        url = C.upyun.slider_url + '/' + aid + '.jpg';
    }
    return url;
};
/*
 * @todo 标签贴图地址
 * @tagid 贴子tagid
 * */
exports.generateTagMarkUrl = function (tagid) {
    var url = "";
    if (tagid > 0) {
        tagid = tagid.toString();
        url = C.upyun.tagmark_url + '/' + tagid + '.png';
    }
    return url;
};

/*
 * @todo 标签通栏图地址
 * @tagid 贴子tagid
 * */
exports.generateTagBannerUrl = function (tagid) {
    var url = "";
    if (tagid > 0) {
        tagid = tagid.toString();
        url = C.upyun.tagbanner_url + '/' + tagid + '.jpg';
    }
    return url;
};

/*
 * @todo 启动画面
 * @tagid 贴子tagid
 * */
exports.generateSplashscreenUrl = function (appid) {
    var url = "";
    if (appid > 0) {
        appid = appid.toString();
        url = C.upyun.splashscreen_url + '/' + appid + '.jpg';
    }
    return url;
};

/**
 *@todo 获取又拍云签名
 *@proc {
 *"imgType": "W",
 *"imgId": "1234567",
 *"imgRandom": "-174851",
 *"imgExt": "jpg",
 *"imgPath": "/o2o/ware/000/12/34/567-174851.jpg",
 *"imgURI": "http://img-test.yueniapp.com/o2o/ware/000/12/34/567-174851.jpg"
 * ...... 如crop
 * proc通过str2imgUrl得到
 }
 */

exports.getUpyunSignGeneral = function*(){
    let bucket = C.upyun.bucket || 'inmm-img';
    let upUrl = C.upyun.upload_url || 'http://v0.api.upyun.com';
    let formApiSecret = C.upyun.api_secret || '6h4Z5LoH0JbgNNDVdeDP4ejvbqc=';
    //参数
    let d=new Date();
    let currentDate=d.toLocaleDateString();
    let currentTime=d.toLocaleTimeString()+"-"+d.getMilliseconds()+"-"+imgRule.getRandom(6);
    let saveKey = '/o2o/common/' + currentDate + '/' + currentTime.replace(':','-').replace(':','-') + ".jpg";
    let options={};
    options['bucket'] = bucket; /// 空间名
    options['expiration'] = new Date().getTime() + 1200; //授权有效期，Unix 时间戳 / 授权过期时间 20min
    options['allow-file-type'] = 'jpg';// 控制文件上传的类型，可选
    options['save-key'] = saveKey;
    options['content-length-range'] = '0,4096000'; /// 限制文件大小，可选
    options['image-width-range'] = '10,5000'; /// 限制图片宽度，可选
    options['image-height-range'] = '10,5000'; /// 限制图片高度，可选
    //生成签名
    let policy = new Buffer(JSON.stringify(options)).toString('base64');
    let sign = md5.digest_s(policy + '&' + formApiSecret);
    //拼接返回数据
    let data = {};
    data['policy'] = policy;
    data['signature'] = sign;
    data['url'] = upUrl + '/' + bucket + '/';
    data['bucket'] = bucket;
    data.saveKey = saveKey;
    return data;
};

exports.getUpyunSignB = function*(proc) {
  let bucket = C.upyun.bucket || 'inmm-img';
  let upUrl = C.upyun.upload_url || 'http://v0.api.upyun.com';
  let formApiSecret = C.upyun.api_secret || '6h4Z5LoH0JbgNNDVdeDP4ejvbqc=';
    //参数
    let options={};
    options['bucket'] = bucket; /// 空间名
    options['expiration'] = new Date().getTime() + 1200; //授权有效期，Unix 时间戳 / 授权过期时间 20min
  if (proc.crop) options['x-gmkerl-crop'] = proc.crop;//图片裁剪，格式：x,y,width,height，均需为正整型
  let saveKey = proc.imgPath;
  options['allow-file-type'] = C.upyun.urlTypeArray[proc.imgType].imgExt.toString();// 控制文件上传的类型，可选
  /*
   if (proc.imgType == 'A' || proc.type == 1) {//人 avatar 头像
   options['allow-file-type'] = 'jpg,jpeg';// 控制文件上传的类型，可选
   } else if (proc.imgType == 'P' || proc.type == 2) {//帖子
   options['allow-file-type'] = 'jpg,jpeg';
   } else if (proc.imgType == 'T' || proc.type == 3) {//标签图片
   options['allow-file-type'] = 'jpg,jpeg,png';
   } else if (proc.imgType == 'SD' || proc.type == 4) {//轮播图片
   options['allow-file-type'] = 'jpg,jpeg,png';
   } else if (proc.imgType == 'TM' || proc.type == 5) {//标签贴图
   options['allow-file-type'] = 'png';
   } else if (proc.imgType == 'TB' || proc.type == 6) {//标签通栏图
   options['allow-file-type'] = 'jpg,jpeg,png';
   } else if (proc.imgType == 'SP' || proc.type == 7) {//启动画面
   options['allow-file-type'] = 'jpg,jpeg';
   } else if (proc.imgType == 'H' || proc.type == 8) {//H5图片
   options['allow-file-type'] = 'jpg,jpeg,png';
   } else if (proc.imgType == 'V' || proc.type == 9) {//商家图片
   options['allow-file-type'] = 'jpg,jpeg,png';
   } else if (proc.imgType == 'S' || proc.type == 10) {//门店图片
   options['allow-file-type'] = 'jpg,jpeg,png';
   } else if (proc.imgType == 'W' || proc.type == 11) {//商品图片
   options['allow-file-type'] = 'jpg,jpeg,png';
    }
   */
    options['save-key'] = saveKey;
    options['content-length-range'] = '0,4096000'; /// 限制文件大小，可选
    options['image-width-range'] = '10,5000'; /// 限制图片宽度，可选
    options['image-height-range'] = '10,5000'; /// 限制图片高度，可选
    //生成签名
  let policy = new Buffer(JSON.stringify(options)).toString('base64');
  let sign = md5.digest_s(policy + '&' + formApiSecret);
    //拼接返回数据
  let data = {};
    data['policy'] = policy;
    data['signature'] = sign;
    data['url'] = upUrl + '/' + bucket + '/';
    data['bucket'] = bucket;
  data.saveKey = saveKey;
    return data;
}


/*
 @todo 获取又拍云签名
 @proc {type=1,uid=xx} 头像处理
 *     {type=2,pid=xx,imgBack(1 jpg 2 gif 3 png)} 贴子或其他图片处理
 *     {type=3,tagid=xx} 上传标签图片
 *     {type=4,o2oImg{}}
 */
exports.getUpyunSign = function*(proc) {
    var bucket = C.upyun.bucket || 'inmm-img';
    var upUrl = C.upyun.upload_url || 'http://v0.api.upyun.com';
    var formApiSecret = C.upyun.api_secret || '6h4Z5LoH0JbgNNDVdeDP4ejvbqc=';
    var options = {};
    if (proc.crop) {
        options['x-gmkerl-crop'] = proc.crop;
    }
    options['bucket'] = bucket; /// 空间名
    options['expiration'] = new Date().getTime() + 1200; //授权有效期，Unix 时间戳 / 授权过期时间 20min
    if (proc['type'] == 1) {//人
        var uid = proc['uid'];//登录用户
        var img = _.str.lpad(uid, 9, '0');
        var pos = [3, 6, 9];
        for (var i = 0; i < pos.length; i++) {
            img = _.str.insert(img, pos[i], '/');
        }
        var saveKey = '/avatar/' + img + '.jpg';
        options['allow-file-type'] = 'jpg,jpeg'; /// 控制文件上传的类型，可选
    } else if (proc['type'] == 2) {//帖子
        var imgBack = proc['imgBack'];
        switch (imgBack) {
            case '1':
                imgBack = '.jpg';
                break;
            case '2':
                imgBack = '.gif';
                break;
            case '3':
                imgBack = '.png';
                break;
            default :
                imgBack = '.jpg'
        }
        var pid = proc['pid'];
        var img = _.str.lpad(pid, 10, '0');
        var str = '';
        if (proc['imgindex'] != undefined) {
            if (proc['imgindex'] != 'video') {//当imgindex='video'时，传进来的是视频截图，没有图片索引号
                var imgIndex = parseInt(proc['imgindex']);
            }
            if (imgIndex > 0) {
                str += '-' + imgIndex;
            } else if (proc['imgindex'] == 'video') {
                str += '-' + proc['imgindex'];
            }
        }

        img = img.substring(0, 3) + '/' + img.substring(3, 5) + '/' + img.substring(5, 7) + '/' + img.substring(7) + str;
        var saveKey = '/img/' + img + imgBack;
        options['allow-file-type'] = 'jpg,jpeg'; /// 控制文件上传的类型，可选
  } else if (proc['type'] == 3) { //标签图片

        var tagid = proc['tagId']; //标签id号

        var img = _.str.lpad(tagid, 9, '0');
        var pos = [3, 6, 9];
        for (var i = 0; i < pos.length; i++) {
            img = _.str.insert(img, pos[i], '/');
        }
        var saveKey = '/tag/' + img + '.jpg';
        options['allow-file-type'] = 'jpg,jpeg,png'; /// 控制文件上传的类型，可选
    } else if (proc['type'] == 4) {//轮播图片
        var aid = proc['aid'];//sliderId
        var saveKey = '/slider/' + aid + '.jpg';
        options['allow-file-type'] = 'jpg,jpeg,png'; /// 控制文件上传的类型，可选
    } else if (proc['type'] == 5) {//标签贴图
        var tagid = proc['tagId'];//tagId
        var saveKey = '/tagmark/' + tagid + '.png';
        options['allow-file-type'] = 'png'; /// 控制文件上传的类型，可选
    } else if (proc['type'] == 6) {//标签通栏图
        var tagid = proc['tagId'];//tagId
        var saveKey = '/tagbanner/' + tagid + '.jpg';
        options['allow-file-type'] = 'jpg,jpeg,png'; /// 控制文件上传的类型，可选
    } else if (proc['type'] == 7) {//启动画面
        var appId = proc['appId'];//tagId
        var saveKey = '/splashscreen/' + appId + '.jpg';
        options['allow-file-type'] = 'jpg,jpeg'; /// 控制文件上传的类型，可选
    } else if (proc['type'] == 8) {//H5图片
        var fileName = proc['filename'];
        var saveKey = '/h5/h/' + fileName + '.jpg';
        options['allow-file-type'] = 'jpg,jpeg,png'; /// 控制文件上传的类型，可选
    }
    options['save-key'] = saveKey;
    options['content-length-range'] = '0,4096000'; /// 限制文件大小，可选
    options['image-width-range'] = '10,5000'; /// 限制图片宽度，可选
    options['image-height-range'] = '10,5000'; /// 限制图片高度，可选
    var policy = new Buffer(JSON.stringify(options)).toString('base64');
    var sign = md5.digest_s(policy + '&' + formApiSecret);
    var data = {};
    data['policy'] = policy;
    data['signature'] = sign;
    data['url'] = upUrl + '/' + bucket + '/';
    data['bucket'] = bucket;
    return data;
};

/*
 @todo 检查内容是否含有敏感字
 @content 需要检查的内容
 */
exports.isHaveSensitive = function (content) {
    var isHave = false;
    var badWords = /共产党/g;
    if (badWords.test(content)) {
        isHave = true;
    }
    return isHave;
};

/*
 @todo 添加动态信息
 @logId 登录者id
 @typeId 1发帖 2回帖 3关注人 4订阅标签 5 帖子中标记某人
 @operateId 对应的贴子、用户、标签id
 @authorId 发帖人
 */
exports.addDynamicInfo = function*(logId, typeId, operateId, authorId, pid, reply) {
    var iid = 0;
    var uid = 0;
    var tid = 0;
    var tagId = 0;
    var tempPid = 0;
    var tempReply = 0;
    var logId_ismamager = (logId > 0 ? 0 : 1);
    logId = Math.abs(logId);

    if (_.v.isInt(pid) && parseInt(pid) > 0) {
        tempPid = pid;
    }
    if (reply == 1) {
        tempReply = 1;
    }
    //判断回复马甲或者发帖时@马甲（typeid=2），发帖时添加马甲作为标签(typeid=5)
    var u_isvest = (typeId > 0 ? 0 : 1);
    typeId=Math.abs(typeId);
    switch (typeId) {
        case 1:
            uid = logId;
            tid = operateId;
            tempPid = authorId;
            break;
        case 2:
            uid = authorId;
            tid = operateId;
            break;
        case 3:
            uid = operateId;
            mysql.query("DELETE FROM mh_dynamic_info WHERE type_id=? AND authorid=? AND uid=?", [3, logId, uid]);
            break;
        case 4:
            tagId = operateId;
            mysql.query("DELETE FROM mh_dynamic_info WHERE type_id=? AND authorid=? AND tagid=?", [4, logId, tagId]);
            break;
        case 5:
            uid = authorId;//被标记用户id
            tid = operateId;//具体在哪张帖子中
            break;
    }
    var dInfo = yield mysql.query("INSERT INTO mh_dynamic_info(authorid,type_id,uid,tid,tagid,timeline,pid,reply,a_ismanager,u_isvest) VALUES(?,?,?,?,?,UNIX_TIMESTAMP(),?,?,?,?)", [logId, typeId, uid, tid, tagId, tempPid, tempReply, logId_ismamager,u_isvest]);
    if (dInfo) {
        var iid = dInfo.insertId;
    }
    return iid;
};
/*
 @todo 更新用户详细中的贴子数
 */
exports.memberCount = function* (uid, option) {
    var flag = yield MUsers.editUserDetail(option, "uid=?", [uid]);
    return flag;
};

/*
 * @TODO 点赞/取消点赞 后操作
 * */
exports.afterLike = function*() {

};


/*
 * @TODO 友盟推送广播消息
 * @os_type 0: 全部设备 1:android设备  2:ios设备
 * @device_token android设备44位，ios设备64位
 * @data act=1时: 跳到用户中心 uid
 *       act=2时: 跳到帖子 tid
 *       act=3时：跳到 H5 页面
 *       production_mode: true/false  默认为 true 正式发布; false 仅发给所有测试机用户
 */
exports.umengBroadcast = function (os_type, act, data, productionmode) {
    var timestamp = new Date().getTime();
    var android_appkey = C.umeng.android_appkey;
    var android_app_master_secret = C.umeng.android_app_master_secret;
    var ios_appkey = C.umeng.ios_appkey;
    var ios_app_master_secret = C.umeng.ios_app_master_secret;

    var android_validation_token = md5.digest_s(android_appkey + android_app_master_secret + timestamp);
    var ios_validation_token = md5.digest_s(ios_appkey + ios_app_master_secret + timestamp);
    var production_mode = (productionmode == 1 ? 'true' : 'false'); // 默认为正式发布

    var custom = {};
    custom.title = data.title;
    custom.msg = data.msg;
    custom.act = act;

    if (act == 1) { // 跳到用户中心 uid
        if (!data.id) return {status: false};
        custom.uid = data.id;
    } else if (act == 2) { // 跳到帖子 tid
        if (!data.id) return {status: false};
       //验证data.type类型[undefined和整数]
       // if(data.type !=undefined && !_.v.isInt(data.type)){
       //     return {status: false};
       // }
        custom.type = data.type==undefined || parseInt(data.type)!=2 ? 1:2;
        custom.tid = data.id;
    } else if (act == 3) { // 跳到 H5 页面
        if (!data.URL) return {status: false};
        custom.URL = data.URL;
    } else {
        return {status: false};
    }

    // 推送安卓广播
    if (os_type == 0 || os_type == 1) {
        var options = {
            url: 'http://msg.umeng.com/api/send', // 'http://localhost:8080/api/v1/MSG',
            headers: {
                'User-Agent': 'request'
            },
            method: 'POST',
            json: {
                'appkey': android_appkey,
                'timestamp': timestamp,
                'validation_token': android_validation_token, //'appkey, app_master_secret和timestamp的MD5的sum'
                'type': 'broadcast', //广播
                'payload': {
                    'display_type': 'message',
                    'body': {
                        'custom': custom
                    }
                },
                'description': custom.title,
                'production_mode': production_mode
            }
        };
        async_request.post(options, function (error, response, body) {
            if (error) {
                return console.error('UmengSeng Broad ERROR:', error);
            }
        });
    }

    // 推送ios广播
    if (os_type == 0 || os_type == 2) {
        var options = {
            url: 'http://msg.umeng.com/api/send', // 'http://localhost:8080/api/v1/MSG',
            headers: {
                'User-Agent': 'request'
            },
            method: 'POST',
            json: {
                'appkey': ios_appkey,
                'timestamp': timestamp,
                'validation_token': ios_validation_token,
                'type': 'broadcast', //广播
                'payload': {
                    'aps': {
                        'alert': custom.title,
                        'badge': 1,
                        'custom': custom,
                        'sound': 'default'
                    }
                },
                'production_mode': production_mode
            }
        };
        async_request.post(options, function (error, response, body) {
            if (error) {
                return console.error('UmengSeng Broad ERROR:', error);
            }
        });
    }

    return {status: true};
};

/*
 * @TODO 友盟推送单播消息
 * @os_type 1:android设备  2:ios设备
 * @device_token android设备44位，ios设备64位
 * @data act=1时: {nickname,uid} 关注
 *       act=2时: {nickname,tid} 回复
 *       act=3时： {nickname,tid} 点赞
 *       act=4时:  {nickname,tid} @
 *       act=5时： H5
 *       act=6时： 帖子中标记某人
 */
exports.umengSendMsg = function (os_type, device_token, act, data) {
    var timestamp = new Date().getTime();
    var appkey = '';
    if (os_type == 1) {
        appkey = C.umeng.android_appkey;
        var app_master_secret = C.umeng.android_app_master_secret;
    } else if (os_type == 2) {
        appkey = C.umeng.ios_appkey;
        var app_master_secret = C.umeng.ios_app_master_secret;
    } else {
        return {status: false};
    }

    var custom = {};
    if (act == 1) {
        custom.act = 1;
        custom.title = data.nickname + '关注了您';
        custom.uid = data.uid;
    } else if (act == 2) {
        custom.act = 2;
        custom.title = data.nickname + '回复了您的帖子';
        custom.msg = data.msg;
        custom.tid = data.tid;
    } else if (act == 3) {
        custom.act = 2;
        custom.title = data.nickname + '赞了您的帖子';
        custom.msg = data.msg;
        custom.tid = data.tid;
    } else if (act == 4) {
        custom.act = 2;
        custom.title = data.nickname + '回复了您';
        custom.msg = data.msg;
        custom.tid = data.tid;
    } else if (act == 5) {
        custom.act = 3;
        custom.title = '新年活动';
        custom.msg = '奖品多多';
        custom.URL = 'http://www.yueniapp.com/aboutus.html';
    } else if (act == 6) {
        custom.act = 2;
        custom.title = data.nickname + '在帖子中标记了您';
        custom.msg = data.msg;
        custom.tid = data.tid;
    } else {
        return {status: false};
    }

    if (os_type == 1) {
        var options = {
            url: 'http://msg.umeng.com/api/send', // 'http://localhost:8080/api/v1/MSG',
            headers: {
                'User-Agent': 'request'
            },
            method: 'POST',
            json: {
                'appkey': appkey,
                'timestamp': timestamp,
                'validation_token': md5.digest_s(appkey + app_master_secret + timestamp), //'appkey, app_master_secret和timestamp的MD5的sum'
                'type': 'unicast', //单播
                'device_tokens': device_token,
                'payload': {
                    'display_type': 'message',
                    'body': {
                        'custom': custom
                    }
                },
                'production_mode': (C.env == 'production'), // 正式环境中，改为 true
                'description': custom.title

            }
        }
    } else if (os_type == 2) {
        var options = {
            url: 'http://msg.umeng.com/api/send', // 'http://localhost:8080/api/v1/MSG',
            headers: {
                'User-Agent': 'request'
            },
            method: 'POST',
            json: {
                'appkey': appkey,
                'timestamp': timestamp,
                'validation_token': md5.digest_s(appkey + app_master_secret + timestamp), //'appkey, app_master_secret和timestamp的MD5的sum'
                'type': 'unicast', //单播
                'device_tokens': device_token,
                'payload': {
                    'aps': {
                        'alert': custom.title,
                        'badge': 1,
                        'custom': custom,
                        'sound': 'default'
                    }
                },
                'production_mode': (C.env == 'production') // 正式环境中，改为 true
            }
        }
    }
    //var r = yield request(options); //Yay, HTTP requests with no callbacks!
    console.log(options);
    async_request.post(options, function (error, response, body) {
        if (error) {
            return console.error('UmengSeng ERROR:', error);
        }
    });
    return {status: true};
};


/*
 * @TODO 关注/取消关注 后操作
 * */
exports.afterFriend = function*() {

};

/*
 * @TODO 判断是否包含uid
 * @uid 需要查找的uid
 * @uidList uid列表字符串
 * */
exports.isContainUid = function (uid, uidList) {
    var result = false;
    if (uidList) {
        result = _.str.include(uidList, ',' + uid + ',');
    }
    return result;
};


/*
 * @TODO 楼主被回复后
 * @tid
 * @uid
 * @nickname
 */

exports.afterPost = function*(uid, nickname, tid, post) { //回帖人 uid,nickname,tid,post}
                                                          //yield F.umengSendMsg(1,'Aoda2ZoR_AzuZjQ2Wh-Z2Ivst0z9k2d24MTLMlwmukxz',1,{act:1,nickname:'小猫哥',uid:53});
};


/*
 * @TODO login日志
 * @uid
 * @origin 来源: 1 User/Password,2 Tokenkey
 * @ip
 */

exports.loginLog = function (uid, origin, ip,region) {
    uid = parseInt(uid);
    origin = parseInt(origin);
    mysql.query('insert into mh_login_log(uid,origin,ip,timeline,cityid,city) values(?,?,?,UNIX_TIMESTAMP(),?,?)', [uid, origin, ip,region.city_id,region.city], function () {
    });
    mysql.query('update mh_user SET logintimes = logintimes+1,lastloginip=?,lastlogintime=UNIX_TIMESTAMP() WHERE uid=?', [ip, uid], function () {
    });
    mysql.query('update mh_user_info SET lastestregionid = ? WHERE uid=?', [region.city_id,uid], function () {
    });
};

/*
 * @TODO 友盟推送晚间勿扰模式
 * @disturb 用户勿扰值 1勿扰0推送
 * rerutn true推送false不推送
 */

exports.disturb = function*(disturb) {
    var myDate = new Date();
    var h = parseInt(myDate.getHours());
    var beginTime = parseInt(C.disturb.beginTime) || 8;
    var endTime = parseInt(C.disturb.endTime) || 23;
    if (disturb == 1 && h >= beginTime && h < endTime) {
        return true;
    } else if (disturb == 0) {
        return true;
    }
    return false;
};

/*
 * @TODO 判断标签是否有效
 * @tags 标签
 * rerutn
 */

exports.isTagValid = function*(tags) {
    var returnMsg = {
        flag: true,
        msg: '有效'
    };
    for (var i in tags) {
        var tagData = tags[i];
        var tagsType = parseInt(tagData.tagsType);
        var tagsid = parseInt(tagData.tagsid);
        switch (tagsType) {
            case 1://传统标签
            case 5://水印标签
            case 6://美容标签
                var tagData = yield mysql.query('SELECT tagid,tagtitle FROM mh_tags WHERE tagid=?', [tagsid]);
                if (tagData.length == 0) {
                    returnMsg.flag = false;
                    returnMsg.msg = '标签不存在';
                    return returnMsg;
                }
                break;
            case 2://用户标签
                var userData = yield mysql.query('SELECT uid FROM mh_user WHERE uid=?', [tagsid]);
                if (userData.length == 0) {
                    returnMsg.flag = false;
                    returnMsg.msg = '用户不存在';
                    return returnMsg;
                }
                break;
            case 3://帖子标签
                var threadData = yield mysql.query('SELECT tid FROM mh_thread WHERE tid=?', [tagsid]);
                if (threadData.length == 0) {
                    returnMsg.flag = false;
                    returnMsg.msg = '帖子不存在';
                    return returnMsg;
                }
                break;
            case 4://url
                break;
            default:
                returnMsg.flag = false;
                returnMsg.msg = '参数错误';
                return returnMsg;
                break;
        }
    }
    return returnMsg;
};
/**
 *@todo 返回缓存帖子信息
 * @param tid 可为单个id，可为id数组
 * @returns hash
 */
exports.returnThreadInfo = function*(tid) {
    var key = C.redisPre.thread_info;
    var threadData = yield redisCo.mhgetthread(2, key, C.redisPre.thread_ttl, tid);
    var threadData = JSON.parse(threadData);
    var loseItems = threadData.loseItems;
    for (var i in threadData.items) {
        if (!_.isEmpty(threadData.items[i])) {
            this.intArray(threadData.items[i]);
        }
    }
    if (!_.isEmpty(loseItems)) {
        var tidStr = '';
        for (var i in loseItems) {
            tidStr += tidStr == '' ? i : ',' + i;
        }
        var threads = yield mysql.query('SELECT t.tid,t.pid,t.uid,u.nickname,u.face,u.vip,t.timeline,t.views,t.replies,t.liketimes,p.imgext,IFNULL(pc.post,"") post,IFNULL(pc.imgdesc,"") imgdesc,t.closed,t.`status`,t.digest,t.favtimes,t.sharetimes,t.fid,t.type ttype,t.imgcount,t.imagestring,t.validimg,t.ctype, ' +
            'ui.talentid,ui.integral,t.video,t.vest as isVest, ' +
            't.cid,mtc.name as categoryname ' +
                //'(SELECT lid FROM mh_level WHERE (SELECT integral FROM mh_user_info WHERE uid=t.uid) BETWEEN range_l AND range_h) `level` ' +
            'FROM mh_thread t ' +
            'LEFT JOIN mh_user u ON u.uid = t.uid LEFT JOIN mh_post p ON p.pid = t.pid LEFT JOIN mh_post_content pc ON pc.pid = t.pid ' +
            'LEFT JOIN mh_user_info ui ON ui.uid = t.uid ' +
            'LEFT JOIN mh_thread_category mtc ON mtc.cid=t.cid ' +
            'WHERE t.tid in(' + tidStr + ') GROUP BY t.tid ORDER BY t.tid DESC');
        for (var i in threads) {
            // 计算等级，然后删除经验值
            var level = this.getLevelfromIntegral(threads[i].integral);
            threads[i].level = level.lid;
            delete threads[i].integral;

            //显示达人称号
            //显示达人等级
            if (threads[i].talentid > 0 && threads[i].vip == 0) {// 是否达人  (VIP 无达人属性)
                threads[i].talent = this.getTalentInfo(threads[i].talentid).name;
                threads[i].talent_level = level.talent_level; //  this.getTalentInfo(threads[i].talentid).talent_level;
            } else {
                threads[i].talent = '';
                threads[i].talentid = 0
            }

            threads[i].tags = JSON.stringify([]);
            var threadTagData = yield mysql.query('SELECT tagsid,tagstype tagsType,tagstitle,x,y,imgindex,poiid,placeLeft FROM mh_thread_tags WHERE tid=? and tagstype!=99 order by tagsType desc', [parseInt(threads[i].tid)]);
            if (threadTagData.length > 0) {
                for (var j in threadTagData) {
                    if (threadTagData[j].placeLeft == 2) {
                        threadTagData[j].placeLeft = threadTagData[j].x > 50 ? 1 : 0;
                    }
                    switch (threadTagData[j].tagsType) {
                        case 1://传统标
                        case 5://水印标签
                            threadTagData[j].tagstitle = '';
                            var tagData = yield mysql.queryOne('SELECT tagtitle FROM mh_tags WHERE tagid=?', [parseInt(threadTagData[j].tagsid)]);
                            if (tagData) {
                                threadTagData[j].tagstitle = tagData['tagtitle'];
                            }
                            break;
                        case 6://美容标签
                            delete threadTagData[j].x;
                            delete threadTagData[j].y;
                            delete threadTagData[j].imgindex;
                            delete threadTagData[j].placeLeft;
                    }
                    if (threadTagData[j].tagsType != 4) {//lsb才有poiid属性
                        delete threadTagData[j].poiid;
                    }
                }
                threads[i].tags = JSON.stringify(threadTagData);
            }
            threads[i].likeusers = JSON.stringify([]);
            var threadLikeData = yield mysql.query('SELECT ml.uid,mu.face FROM mh_likes ml LEFT JOIN mh_user mu ON ml.uid=mu.uid WHERE ml.tid=? and ml.first=1 ORDER BY ml.timeline DESC LIMIT 0,10', [parseInt(threads[i].tid)])
            if (threadLikeData.length > 0) {
                threads[i].likeusers = JSON.stringify(threadLikeData);
            }
            if (threads[i].ttype > 0 || threads[i].fid>0) {//整形帖
                if (threads[i].fid == 0) {
                    var obj = yield mysql.queryOne('SELECT orderid,dailyNum,title,wareid,wareName,IFNULL(price,0) as price,consumeDate,firstDate,categoryId,categoryName,vendorid,vendorName,imageBefore,imageAfter,doctor,shopid,shopName,IFNULL(operationPrice,0) as operationPrice from mh_thread_extend where tid=?', [parseInt(threads[i].tid)]);
                    if (obj) {
                        //threads[i].orderid = obj.orderid;
                        threads[i].dailyNum = obj.dailyNum||0;
                        threads[i].title = obj.title;
                        threads[i].operationPrice = obj.operationPrice;
                        threads[i].firstDate = obj.firstDate;
                        threads[i].doctor  = obj.doctor||'';
                        //threads[i].wareCategoryid = obj.categoryId||0;//不需要此属性，只需要圈子类别
                        //threads[i].wareCategoryName = obj.categoryName||'';//不需要此属性，只需要圈子类别
                        threads[i].imageBefore=_.isEmpty(obj.imageBefore)?'':imgRule.str2imgURI(obj.imageBefore)[0].imgURI+ C.upyun.suffix;
                        threads[i].imageAfter=_.isEmpty(obj.imageAfter)?'':imgRule.str2imgURI(obj.imageAfter)[0].imgURI+ C.upyun.suffix;
                        threads[i].duration=1;//首帖默认为1
                        if(threads[i].ttype ==1){//关联商品的美容贴字段
                            threads[i].price = obj.price;
                            threads[i].wareImageUrl = '';
                            threads[i].wareid  = obj.wareid||0;
                            threads[i].wareName = obj.wareName||'';
                            threads[i].consumeDate = obj.consumeDate;
                            threads[i].vendorid = obj.vendorid||0;
                            threads[i].vendorName = obj.vendorName||'';
                            var o2oF = require('../common/o2ofunction');
                            var wareDetail = yield o2oF.o2oGetWareInfoByWareId(threads[i].wareid);
                            if (!(parseInt(wareDetail['result']['error']) == 1 || wareDetail.status == 400)) {
                                if(wareDetail['result'].images.length>0){
                                    threads[i].wareImageUrl = wareDetail['result'].images[0];
                                }
                            }
                        }else if(threads[i].ttype ==2){//没有关联商品的美容贴字段
                            threads[i].shopid = obj.shopid||0;
                            threads[i].shopName = obj.shopName||'';
                            //let operationTags=[];
                            //let tagsData=yield mysql.query('SELECT tagsid,tagstype,tagstitle from mh_thread_tags where tid=?',[threads[i].tid]);
                            //for(let tag of tagsData){
                            //    operationTags.push(tag);
                            //}
                            //threads[i].tags= JSON.stringify(operationTags);
                        }
                    }
                }else{
                    //this.dateDiff
                    var dailyThread=yield mysql.queryOne('SELECT timestampdiff(day,FROM_UNIXTIME(mtf.timeline, \'%Y-%m-%d\'),FROM_UNIXTIME(mt.timeline, \'%Y-%m-%d\'))+1 duration,mte.dailyNum '+
                                                        'from mh_thread mtf inner join mh_thread mt on mtf.tid=mt.fid inner join mh_thread_extend mte on mte.tid=mtf.tid  where mt.tid=?',[parseInt(threads[i].tid)]);
                    if(dailyThread){
                        threads[i].duration=dailyThread.duration;
                        threads[i].dailyNum=dailyThread.dailyNum;
                    }
                }
            }
            threads[i].postusers = JSON.stringify([]);
            var postUserseData = yield MPosts.getPostUsers({"tid": parseInt(threads[i].tid)});
            if (postUserseData.length > 0) {
                threads[i].postusers = JSON.stringify(postUserseData);
            }
            threads[i].post = _.str.unescapeHTML(threads[i].post);
            var key = C.redisPre.thread_info;
            key = _.str.sprintf(key, threads[i].tid);
            redisClient.hmset(key, threads[i]);
            redisClient.expire(key, C.redisPre.thread_ttl);
            threadData.items[parseInt(loseItems[threads[i].tid])] = threads[i];
        }
    }
    return threadData.items;
};

/**
 * @todo 在数组中的数据都将被转为整型
 * @param arr
 */
exports.intArray = function (arr) {
    if (_.isObject(arr)) {
        for (var i in arr) {
            if (_.v.isIn(i, ['uid', 'groupid', 'bodytype', 'face', 'threads', 'favtimes', 'sharetimes', 'views',
                    'posts', 'friends', 'beliked', 'fans', 'tfavtimes', 'pinTags', 'cid','ctype',
                    'dailyNum','duration','fid','isVest','vendorid','wareid',
                    'gender', 'tid', 'pid', 'tagid', 'page', 'pagesize', 'tagcount', 'tagimg', 'pincount',
                   'timeline', 'closed', 'liketimes', 'replies', 'status', 'digest', 'vip', 'ttype', 'level',
                  'plasticthreads','plasticthreads', 'lastupgradetime', 'integral', 'signtimes', 'lastsigntime',
                  'lastnfid', 'lastrmid', 'lastdyid', 'digestthreads', 'talentid', 'talent_level','shopid'])) {
                arr[i] = parseInt(arr[i]);
            }
        }
    }
};

/**
 *@todo 返回缓存用户信息
 * @param uid 用户id
 * @returns hash
 */
exports.returnUserInfo = function*(uid) {
    var key = C.redisPre.user_info;
    var userData = yield redisCo.mhgetuser(2, key, C.redisPre.user_ttl, uid);
    var userData = JSON.parse(userData);
    var loseItems = userData.loseItems;
    for (var i in userData.items) {
        if (!_.isEmpty(userData.items[i])) {
            this.intArray(userData.items[i]);
        }
    }
    if (!_.isEmpty(loseItems)) {
        var useridStr = '';
        for (var i in loseItems) {
            useridStr += useridStr == '' ? i : ',' + i;
        }
        var users = yield mysql.query('SELECT mu.uid,groupid,mu.vip,mu.nickname,IFNULL(mu.mobile,"") mobile,mui.name,mu.bodytype,mu.face,mu.password,mui.threads,' +
            'mui.plasticthreads,mui.allplasticthreads,mui.digestthreads,mui.talentid,' +
            'mui.posts,mui.friends,mui.beliked,mui.fans,mui.tfavtimes,mui.pintagtimes as pinTags,' +
            'mui.pintagtimes as pinTags,mui.gender,' +
            'IFNULL(mui.signature,"") signature,mui.lastdyid,mui.lastrmid,mui.lastnfid,mui.integral,mui.lastsigntime,mui.signtimes,mui.lastupgradetime,' +
            'mui.citycode ' +
                //',IFNULL((SELECT lid FROM mh_level WHERE mui.integral BETWEEN range_l AND range_h),1) `level` ' +
            'FROM mh_user mu LEFT JOIN mh_user_info mui ON mu.uid=mui.uid WHERE  mu.uid in (' + useridStr + ')');

        for (var i in users) {
            // 所在城市
            var cityInfo = this.getCityInfo(users[i]['citycode']);
            if (!_.isEmpty(cityInfo)) {
                users[i]['city'] = (cityInfo.province != cityInfo.city ? cityInfo.province + ' ' + cityInfo.city : cityInfo.city);
            } else {
                users[i]['city'] = '';
                users[i]['citycode'] = '';
            }
            var level = this.getLevelfromIntegral(users[i].integral);
            // 计算等级
            users[i].level = level.lid;

            //显示达人称号
            //显示达人等级
            if (users[i].talentid > 0 && users[i].vip == 0) {// 是否达人  (VIP 无达人属性)
                users[i].talent = this.getTalentInfo(users[i].talentid).name;
                users[i].talent_level = level.talent_level; //  this.getTalentInfo(threads[i].talentid).talent_level;
            } else {
                users[i].talent = '';
                users[i].talentid = 0
            }

            var key = _.str.sprintf(C.redisPre.user_info, users[i].uid);
            users[i].hasPassword = 0;
            if (!_.isEmpty(users[i].password)) {//是否设定密码
                users[i].hasPassword = 1;
            }
            delete users[i].password;//缓存前先删除pwd信息
            redisClient.hmset(key, users[i]);
            redisClient.expire(key, C.redisPre.user_ttl);
            userData.items[parseInt(loseItems[users[i].uid])] = users[i];
        }
    }
    return userData.items;
};

/**
 *@todo 返回缓存标签信息
 * @param tagid 标签id
 * @returns hash
 */
exports.returnTagInfo = function*(tagid, type) {
    var key = C.redisPre.tag_info;
    var tagData = yield redisCo.mhgettag(3, key, type, C.redisPre.tag_ttl, tagid);
    var tagData = JSON.parse(tagData);
    var loseItems = tagData.loseItems;
    for (var i in tagData.items) {
        if (!_.isEmpty(tagData.items[i])) {
            this.intArray(tagData.items[i]);
        }
    }
    if (!_.isEmpty(loseItems)) {
        if (type == 1) {//传统标签
            var tagidStr = '';
            for (var i in loseItems) {
                tagidStr += tagidStr == '' ? i : ',' + i;
            }
            var tags = yield mysql.query('SELECT tagid,tagtype,IFNULL(tagtitle,"") tagtitle,tagcount,pincount,tagimg,tagdesc,fid,fix FROM mh_tags WHERE tagid in (' + tagidStr + ')');
            for (var i in tags) {
                var key = C.redisPre.tag_info;
                key = _.str.sprintf(key, tags[i].tagid, type);

                tags[i].pinusers = JSON.stringify([]);
                var tagPinData = yield mysql.query('SELECT mp.uid,mu.face FROM mh_pintag mp LEFT JOIN mh_user mu ON mp.uid=mu.uid WHERE mp.tagid=? ORDER BY mp.timeline DESC LIMIT 0,10', [parseInt(tags[i].tagid)])
                if (tagPinData.length > 0) {
                    tags[i].pinusers = JSON.stringify(tagPinData);
                }

                redisClient.hmset(key, tags[i]);
                redisClient.expire(key, C.redisPre.tag_ttl);
                tagData.items[parseInt(loseItems[tags[i].tagid])] = tags[i];
            }
        } else if (type == 4) {//地理位置信息

        }
    }
    return tagData.items;
};

/**
 *
 * @param type type=1 订阅的标签列表: tagid type=2 关注的好友列表: uid type=3 收藏的帖子列表: tid  type=4 点赞的帖子列表: tid
 * $param
 */
    exports.userList = function*(uid, type, beginIndex, pageSize) {
    var userList = '';
    if (_.v.isInt(uid) && _.v.isIn(type, [1, 2, 3, 4,5])) {
        var key = C.redisPre.user_list;
        key = _.str.sprintf(key, uid, type);
        var temp = yield redisCo.expire(key, C.redisPre.user_list_ttl);
        if (temp == 0) {
            var sql = '';
            switch (type) {
                case 1:
                    sql = 'SELECT tagid tempid,timeline FROM mh_pintag WHERE uid=? ORDER BY timeline DESC';
                    break;
                case 2:
                    sql = 'SELECT fuid tempid,timeline FROM mh_friend WHERE uid=? ORDER BY timeline DESC';
                    break;
                case 3:
                    sql = 'SELECT tid tempid,timeline FROM mh_fav WHERE uid=? ORDER BY timeline DESC';
                    break;
                case 4:
                    sql = 'SELECT pid tempid,timeline FROM mh_likes WHERE uid=? and first=1 ORDER BY timeline DESC';
                    break;
                case 5:
                    sql='SELECT pid tempid,timeline FROM mh_likes WHERE uid=? and first=0 ORDER BY timeline DESC';
            }
            var listData = yield mysql.query(sql, [uid]);
            var arr = [];
            arr[0] = key;
            if (listData.length > 0) {
                for (var i in listData) {
                    arr.push(listData[i]['timeline']);
                    arr.push(listData[i]['tempid']);
                }
                if (type == 2) {//好友列表时把系统管理员加进去
                    for (var i in C.sns.manager_uid) {
                        arr.push(1);
                        arr.push(C.sns.manager_uid[i]);
                    }
                }
                yield redisCo.ZADD(arr);
                redisClient.expire(key, C.redisPre.user_list_ttl);
            } else {
                if (type == 2) {//好友列表时把系统管理员加进去
                    for (var i in C.sns.manager_uid) {
                        arr.push(1);
                        arr.push(C.sns.manager_uid[i]);
                    }
                    yield redisCo.ZADD(arr);
                    redisClient.expire(key, C.redisPre.user_list_ttl);
                }
            }
        }
        if (parseInt(beginIndex) >= 0 && parseInt(pageSize) >= 1) {//有分页
            var endIndex = parseInt(beginIndex) + pageSize - 1;
            userList = yield redisCo.zrevrange(key, beginIndex, endIndex);
        } else {
            userList = yield redisCo.zrevrange(key, 0, -1);
        }
    }
    return userList;
};
/**
 * @todo 帖子列表
 * @param tid
 * @param type  type=1
 * @return 帖子最近10个点赞的用户列表
 */
exports.threadList = function*(tid, type) {
    var threadList = [];
    if (_.v.isInt(tid) && _.v.isIn(type, [1])) {
        var key = C.redisPre.thread_list;
        key = _.str.sprintf(key, tid, type);
        var temp = yield redisCo.expire(key, C.redisPre.thread_list_ttl);
        if (temp == 0) {
            var sql = '';
            switch (type) {
                case 1:
                    sql = 'SELECT uid tempid FROM mh_likes WHERE tid=? and first=1 ORDER BY timeline DESC LIMIT 0,10';
                    break;
            }
            var listData = yield mysql.query(sql, [tid]);
            if (listData.length > 0) {
                var arr = [];
                arr.push(key);
                for (var i in listData) {
                    arr.push(listData[i]['tempid']);
                }
                yield redisCo.RPUSH(arr);
                redisClient.expire(key, C.redisPre.thread_list_ttl);
            }
        }
        threadList = yield redisCo.LRANGE(key, 0, -1);
    }
    return threadList;
};

/**
 * @todo 标签列表资料
 * @param tagid
 * @param type  type=1 最近10个订阅的用户列表: uid
 * @return 用户id列表
 */
exports.tagList = function*(tagid, type) {
    var tagList = '';
    if (_.v.isInt(tagid) && _.v.isIn(type, [1])) {
        var key = C.redisPre.tag_list;
        key = _.str.sprintf(key, tagid, type);
        var temp = yield redisCo.expire(key, C.redisPre.tag_list_ttl);
        if (temp == 0) {
            var sql = '';
            switch (type) {
                case 1:
                    sql = 'SELECT uid tempid FROM mh_pintag WHERE tagid=? ORDER BY timeline DESC LIMIT 0,10';
                    break;
            }
            var listData = yield mysql.query(sql, [tagid]);
            if (listData.length > 0) {
                var arr = [];
                arr.push(key);
                for (var i in listData) {
                    arr.push(listData[i]['tempid']);
                }
                yield redisCo.RPUSH(arr);
                redisClient.expire(key, C.redisPre.tag_list_ttl);
            }
        }
        tagList = yield redisCo.LRANGE(key, 0, -1);
    }
    return tagList;
};

/**
 * @todo 列表（帖子）
 * @param type type=0最新 type={uid}发帖
 * @param beginIndex 开始索引
 * @param pageSize 每页显示大小
 * @return 帖子id列表
 */
exports.list = function*(type, beginIndex, pageSize, lastId) {
    var list = [];
    if (type == 0) {//最新帖子
        var key = C.redisPre.lists_news;
        var expire = C.redisPre.lists_news_ttl;
        key = _.str.sprintf(key, type);
        var temp = yield redisCo.expire(key, expire);
        if (temp == 0) {
            yield this.newestThreadListCache();//最新帖子写入缓存
        }
        if (lastId != undefined && parseInt(lastId) >= 0) {
            var beginIndex = 0;
            if (parseInt(lastId) > 0) {
                beginIndex = yield redisCo.ZREVRANK(key, lastId);
                beginIndex = parseInt(beginIndex) + 1;
            }
        }
        if (parseInt(beginIndex) >= 0 && parseInt(pageSize) >= 1) {//有分页
            var endIndex = parseInt(beginIndex) + pageSize - 1;
            var tidArr = yield redisCo.zrevrange(key, beginIndex, endIndex);
            if (beginIndex == 0) {//第一页插进管理发的最后一条帖子
                var aid = C.threadup.newest;
                if (aid > 0) {
                    var sliderData = yield mysql.query('SELECT id FROM mh_slider WHERE aid=? AND sstype=6 AND type=3', [aid]);
                    if (sliderData.length > 0 && parseInt(sliderData[0].id) > 0) {
                        tidArr.unshift(sliderData[0].id);//把帖子推进第一条
                        for (var i in tidArr) {//如果发现后面有帖子就删除
                            if (i > 0 && tidArr[i] == sliderData[0].id) {
                                tidArr.splice(i, 1);
                            }
                        }
                    }
                }
                //yield this.usersThreadCache(C.sns.manager_uid);//写管理员发帖，只写tid
                //var manTidArr=yield this.userThreadList(C.sns.manager_uid,0,1,0);//取得最后一条
                //if(manTidArr.length>0){
                //  tidArr.unshift(manTidArr[0]);//把管理发的帖子推进第一条
                //  for(var i in tidArr){//如果发现后面有管理的发的帖子就删除
                //    if(i>0&&tidArr[i]==manTidArr[0]){
                //      tidArr.splice(i,1);
                //    }
                //  }
                //}
            }
        } else {
            var tidArr = yield redisCo.zrevrange(key, 0, -1);
        }
        if (tidArr.length > 0) {
            list = yield this.returnThreadInfo(tidArr);
        }
    } else {//某人好友发主题帖
        var friend = yield this.userList(type, 2);//取得好友
        friend.push(type);
        if (!_.isEmpty(friend)) {
            var key = C.redisPre.lists_user;
            var expire = C.redisPre.lists_user_ttl;
            var noThreadUser = yield redisCo.mhgetnothreaduid(2, key, expire, friend);//返回帖子缓存的uid（数组）
            noThreadUser = JSON.parse(noThreadUser);
            yield this.usersThreadCache(noThreadUser.loseItems);//写每个人对应的发帖，只写tid
            var tidArr = yield this.userThreadList(friend, beginIndex, pageSize, lastId);//
            if (tidArr.length > 0) {
                list = yield this.returnThreadInfo(tidArr);
            }
        }
    }
    return list;
};
/**
 * @todo 合并用户的帖子
 * @param uidArr 用户id数组
 */
exports.userThreadList = function*(uidArr, beginIndex, pageSize, lastId) {
    var returnData = '';
    if (_.isArray(uidArr)) {
        var expire = C.redisPre.lists_user_ttl;
        var keyArr = [];
        var outPut = 'output';
        for (var i in uidArr) {
            var key = C.redisPre.lists_user;
            key = _.str.sprintf(key, parseInt(uidArr[i]));
            var temp = yield redisCo.expire(key, expire);
            if (temp == 0) {

            } else {
                keyArr.push(key);
            }
        }
        var keyArrCount = keyArr.length;
        if (keyArrCount == 0) {
            return [];
        }
        keyArr.unshift(keyArrCount);
        keyArr.unshift(outPut);
        keyArr.push('WEIGHTS');
        for (var j = 0; j < keyArrCount; j++) {
            keyArr.push(1);//权重
        }
        redisClient.DEL(outPut);
        yield redisCo.ZUNIONSTORE(keyArr);
        if (lastId != undefined && parseInt(lastId) >= 0)
            var beginIndex = 0;
        if (parseInt(lastId) > 0) {
            beginIndex = yield redisCo.ZREVRANK(outPut, lastId);
            beginIndex = parseInt(beginIndex) + 1;
        }
        if (parseInt(pageSize) >= 1) {//有分页
            var endIndex = parseInt(beginIndex) + pageSize - 1;
            returnData = yield redisCo.ZREVRANGE(outPut, beginIndex, endIndex);
        } else {
            returnData = yield redisCo.ZREVRANGE(outPut, 0, -1);
        }
    }
    return returnData;
};
/**
 * @todo 用户帖子写入缓存
 * @param uidArr 用户id数组
 */
exports.usersThreadCache = function*(uidArr) {
    if (_.isArray(uidArr)) {
        var expire = C.redisPre.lists_user_ttl;
        for (var i in uidArr) {
            var key = C.redisPre.lists_user;
            key = _.str.sprintf(key, parseInt(uidArr[i]));
            var temp = yield redisCo.expire(key, expire);
            if (temp == 0) {
                var sql = 'SELECT tid FROM mh_thread WHERE uid=? AND `status`=1';
                var tidData = yield mysql.query(sql, [uidArr[i]]);
                if (tidData.length > 0) { // 判断不为空
                    var tidArr = [];
                    tidArr[0] = key;
                    for (var i in tidData) {
                        tidArr.push(parseInt(tidData[i].tid));
                        tidArr.push(parseInt(tidData[i].tid));
                    }
                    yield redisCo.ZADD(tidArr);
                    redisClient.expire(key, expire);
                }
            }
        }
    }
};
/**
 * @todo 更新用户缓存信息
 * @param uid
 * @param updateData
 */
exports.updateUserCache = function*(uid, updateData) {
    if (_.v.isInt(uid) && _.isObject(updateData) && !_.isEmpty(updateData)) {
        var key = C.redisPre.user_info;
        var expire = C.redisPre.user_ttl;
        key = _.str.sprintf(key, parseInt(uid));
        var temp = yield redisCo.expire(key, expire);
        if (temp == 1) {
            redisClient.hmset(key, updateData);//更新用户缓存
        }
    }
};

/**
 * @todo 更新帖子缓存信息
 * @param tid
 * @param updateData
 */
exports.updateThreadCache = function*(tid, updateData) {
    if (_.v.isInt(tid) && _.isObject(updateData) && !_.isEmpty(updateData)) {
        var key = C.redisPre.thread_info;
        var expire = C.redisPre.thread_ttl;
        key = _.str.sprintf(key, parseInt(tid));
        var temp = yield redisCo.expire(key, expire);
        if (temp == 1) {
            redisClient.hmset(key, updateData);//更新用户缓存
        }
    }
};

/**
 * @todo 更新标签缓存信息
 * @param tagid
 * @param updateData
 */
exports.updateTagCache = function*(tagid, updateData) {
    if (_.v.isInt(tagid) && _.isObject(updateData) && !_.isEmpty(updateData)) {
        var key = C.redisPre.tag_info;
        var expire = C.redisPre.tag_ttl;
        key = _.str.sprintf(key, parseInt(tagid), 1);
        var temp = yield redisCo.expire(key, expire);
        if (temp == 1) {
            redisClient.hmset(key, updateData);//更新用户缓存
        }
    }
};

/**
 * @todo 最新帖子列表写入缓存
 */
exports.newestThreadListCache = function*() {
    var key = C.redisPre.lists_news;
    var expire = C.redisPre.lists_news_ttl
    key = _.str.sprintf(key, 0);
    var temp = yield redisCo.expire(key, expire);
    if (temp == 0) {
        var sql = 'SELECT tid tempid FROM mh_thread where 1=1 AND `status` = 1 ORDER BY tid DESC LIMIT 0,' + C.redisPre.lists_init_count;
        var listData = yield mysql.query(sql);
        if (listData.length > 0) {
            var arr = [];
            arr[0] = key;
            for (var i in listData) {
                arr.push(listData[i]['tempid']);
                arr.push(listData[i]['tempid']);
            }
            yield redisCo.ZADD(arr);
            redisClient.expire(key, expire);
        }
    }
};

/**
 * @todo 精华帖子列表写入缓存
 */
exports.digestThreadListCache = function*() {
    var key = C.redisPre.lists_digest;
    var expire = C.redisPre.lists_digest_ttl;
    key = _.str.sprintf(key, 0);
    var temp = yield redisCo.expire(key, expire);
    if (temp == 0) {
        //var sql='SELECT tid tempid FROM mh_thread where 1=1 AND `status` = 1 ORDER BY tid DESC LIMIT 0,'+C.redisPre.lists_init_count;
        //var threadData=yield mysql.query('SELECT tid FROM mh_thread mt WHERE mt. STATUS = 1 AND mt.digest = 1 ORDER BY IF (mt.timeline > (UNIX_TIMESTAMP() - 259200),IF (mt.userreplies > 50,50,mt.userreplies)*2+IF (mt.views > 100, 100, mt.views) * 0.5+IF (vest > 0, 0, 30)+IF (mt.sharetimes > 5,5,mt.sharetimes) * 5+IF (mt.toptimeline >UNIX_TIMESTAMP() ,100,0)+ mt.timeline * 0.0005 - UNIX_TIMESTAMP() * 0.0005 + 300,0)  DESC, mt.lastpost DESC LIMIT ?,?',[beginIndex, pageSize]);

        //let sql='SELECT tid tempid FROM mh_thread mt' +
        //  ' WHERE mt.status = 1 AND mt.digest = 1' +
        //  ' ORDER BY IF (mt.timeline > (UNIX_TIMESTAMP() - 259200),' +
        //  ' IF(mt.vest>0,IF (mt.userreplies > 50,50,mt.userreplies)*2,IF (mt.replies > 50,50,mt.replies)*2) +IF (mt.views > 100, 100, mt.views) * 0.5+IF (vest > 0, 0, 5)+IF (mt.sharetimes > 5,5,mt.sharetimes) * 5+IF (mt.toptimeline >UNIX_TIMESTAMP() ,100,0)+ mt.timeline * 0.0005 - UNIX_TIMESTAMP() * 0.0005 + 300,0)  DESC,' +
        //  ' mt.lastpost DESC' +
        //  ' LIMIT 0,'+C.redisPre.lists_digest_count;

        let sql = 'SELECT tid tempid FROM mh_thread mt WHERE mt.digest=1 AND mt.status=1' +
            ' ORDER BY mt.digesttimeline DESC ' +
            ' LIMIT 0,' + C.redisPre.lists_digest_count;


        var listData = yield mysql.query(sql);
        if (listData.length > 0) {
            var arr = [];
            arr[0] = key;
            for (var i in listData) {
                arr.push(i);
                arr.push(listData[i]['tempid']);
            }
            yield redisCo.ZADD(arr);
            redisClient.expire(key, expire);
        }
    }
};


exports.getDigestList = function*(page, pageSize) {
    let key = C.redisPre.lists_digest;
    let beginIndex = (page - 1) * pageSize;
    let endIndex = beginIndex + pageSize - 1;
    let temp = yield redisCo.EXISTS(key);
    if (temp == 0) {
        yield this.digestThreadListCache();
    }
    let tidArr = yield redisCo.zrange(key, beginIndex, endIndex);
    let ret = [];
    for (let i in tidArr) {
        ret.push({tid: parseInt(tidArr[i])});
    }
    return ret;
};


/**
 *@todo 取得社会化登录帐号信息
 * @mediaType 1 QQ 2 微信
 * @accessToken 接口凭证
 * @returns {*}
 */
exports.oauthLogin = function* (mediaType, accessToken, openId) {
    var appId = C.oauth.app_id_qq;
    switch (parseInt(mediaType)) {
        case 1://悦你QQ登陆
            //appId = C.oauth.app_id_qq_chinaskin;
            var options = {
                url: 'https://graph.qq.com/user/get_user_info?oauth_consumer_key=' + appId + '&access_token=' + accessToken + '&openid=' + openId + '&format=json',
                headers: {'User-Agent': 'request'}
            };
            break;
        case 2:
        case 4://2,悦你微信登陆;4 瓷肌微信登陆
            var options = {
                url: 'https://api.weixin.qq.com/sns/userinfo?access_token=' + accessToken + '&openid=' + openId,
                headers: {'User-Agent': 'request'}
            };
            break;
        //case 3://瓷肌QQ登陆
        //    appId=C.oauth.app_id_qq_chinaskin;
        //  var options = {
        //    url: 'https://graph.qq.com/user/get_user_info?oauth_consumer_key=' + appId + '&access_token=' + accessToken + '&openid=' + openId + '&format=json',
        //    headers: {'User-Agent': 'request'}
        //  };
    }
    var response = yield request(options); //Yay, HTTP requests with no callbacks!
    return response.body;
};

/*
 * @TODO 取得标签关系
 * @type 1 传统标签
 * @id 标签id
 */
exports.getRelation = function* (type, id) {
    var returnData = [];
    if (type == 1) {
        var tagData = yield mysql.query('select tagid,tagtitle,fid from mh_tags where tagid=?', [id]);
        if (tagData.length > 0) {
            returnData.unshift({tagid: tagData[0]['tagid'], tagtitle: tagData[0]['tagtitle']});
            do {
                tagData = yield mysql.query('select tagid,tagtitle,fid from mh_tags where tagid=?', [tagData[0]['fid']]);
                if (tagData.length > 0) {
                    returnData.unshift({tagid: tagData[0]['tagid'], tagtitle: tagData[0]['tagtitle']});
                }
            }
            while (tagData.length != 0 && tagData[0]['fid'] != 0);
        }
    }
    return returnData;
};

/*
 isJson 尝试判断字符串是否为json类型。返回json对象或false
 */
function isJson(str) {
    try {
        return JSON.parse(str);
    } catch (e) {
        return false;
    }
}

exports.isJson = isJson;


/*
 * @TODO 处理插播
 * @type 插播类型 1 发现页主菜单，2 发现页 最新达人
 * @inData 需插播的原数组
 * @data 请求的参数
 * @返回类型 插播后的数组
 */
exports.spots = function* (type, inData, data) {
    if (C.env != 'production') {
        // 非正式环境下的测试插播内容

    }

    var retData = [];
    var tmpData;
    if (type == 1) { //首页菜单
        var tmpData = yield spotsH5();
        if (tmpData.length != 0) {
            //threads.splice(0,0,s3[0]);
            inData.push(tmpData[0]);
        }
    } else if (type == 2) { //最新页面 最新达人
        if (data.act == 7 && data.page == 1 && data.version >= 4) {
            var d = new Date();
            d = d.getHours();//16
            if ((d >= 9 && d < 18) || (d >= 18 && d < 22)) {
                tmpData = yield this.getLatestTalent({type: 3, title: '你感兴趣的人', more: 1});
                if (!_.isEmpty(tmpData)) {
                    inData.push(tmpData);
                }
            }
        }
    }
    return inData;
};

/*
 Send mail
 */
exports.sendEmail = function* (to, subject, body) {
// setup e-mail data with unicode symbols
    var mailOptions = {
        from: '管理员 <' + C.email.username + '>', // sender address
        to: to, // list of receivers
        subject: subject, // Subject line
        text: body // plaintext body
    };
// send mail with defined transport object
    transporter.sendMail(mailOptions, function (error, info) {
        if (error) {
            console.log(error);
        } else {
            console.log('Message sent: ' + info.response);
        }
    });
};
/**
 * @todo 高德根据poiid取得详细信息
 * @param poiId
 * @returns {*}
 */
exports.AMAPSearchPoi = function (poiId, cb) {
    var poiIdStr = poiId.toString();
    var options = {
        url: C.amap.poi_info_url +
        '?key=' + C.amap.api_key +
        '&s=' + C.amap.poi_info_s +
        '&id=' + poiIdStr,
        headers: {
            'Referer': C.amap.referer
        },
        method: 'GET',
        gzip: true
    };

    async_request(options, function (error, response, body) {
        if (!error && response.statusCode == 200) {
            var jsonData = isJson(body);
            if (jsonData && jsonData.count > 0) {
                var poisArr = jsonData.pois;
                if (poisArr.length != 0) {
                    var pois = poisArr[0];
                    var location = pois.location;
                    location = location.split(',');
                    if (_.isArray(pois.address)) {
                        pois.address = pois.address.join('');
                    }

                    if (_.isArray(pois.pcode)) {
                        pois.pcode = pois.pcode.join('');
                    }

                    if (_.isArray(pois.pname)) {
                        pois.pname = pois.pname.join('');
                    }

                    if (_.isArray(pois.citycode)) {
                        pois.citycode = pois.citycode.join('');
                    }

                    if (_.isArray(pois.cityname)) {
                        pois.cityname = pois.cityname.join('');
                    }

                    if (_.isArray(pois.adname)) {
                        pois.adname = pois.adname.join('');
                    }


                    pois.longitude = location[0];//经度
                    pois.latitude = location[1];//纬度
                    cb(jsonData, pois);
                }
            }
        } else {
            console.log(error);
        }
    });
};

/**
 * @todo 生成经验日志
 * @param uid 用户id
 * @param typeId 操作类型 1注册 2签到 3发帖 4自己删帖 5被管理员删帖 6帖子被设为精华 7关注好友 8取消关注好友 9订阅标签
 *                      10取消订阅标签 11收藏帖子 12取消收藏帖子 13点赞 14取消点赞 15回复 16删除自己的回复
 * @param operateId 被操作id
 * @returns {*}
 */
exports.generateIntegralLog = function *(uid, typeId, operateId,fake) {
    var gain = 0;//获得经验
    if (!operateId) {
        operateId = 0;
    }
    if (!_.v.isIn(typeId, C.level_action)) {
        return 0;
    }
    var userInfo = yield this.returnUserInfo(uid);
    var levelData = this.getLevelfromIntegral(parseInt(userInfo[0].integral));
    if (levelData) {
        var gainArr = levelData.reward;
        gain = gainArr[typeId];
        if(fake){
            return gain;
        }
        var integralInfo = yield mysql.query("INSERT INTO mh_integral_log(uid,optype,opid,timeline,gain) VALUES(?,?,?,UNIX_TIMESTAMP(),?)", [uid, typeId, operateId, gain]);
        if (integralInfo.insertId > 0) {
            var updateUserCache = {};
            var oldTntegral = parseInt(userInfo[0].integral);
            var newTntegral = oldTntegral + parseInt(gain);
            if (newTntegral < 0) {
                newTntegral = 0;
            }
            mysql.query('UPDATE mh_user_info SET integral=? WHERE uid=?', [newTntegral, uid]);//给用户增减经验
            updateUserCache.integral = newTntegral;
            levelData = this.getLevelfromIntegral(newTntegral);
            if (levelData.lid != parseInt(userInfo[0].level)) {//如果加分后到达升级分数线
                updateUserCache.level = parseInt(levelData.lid);
                updateUserCache.lastupgradetime = this.timestamp();
                var userThread = yield mysql.query('SELECT tid FROM mh_thread WHERE uid=? and `status`=1', [uid]);
                if (userThread.length > 0) {
                    var tidArr = [];
                    for (var i in userThread) {
                        tidArr.push(userThread[i].tid);
                    }
                    var key = C.redisPre.thread_info;
                    var expire = C.redisPre.thread_ttl;
                    yield this.redisCo.mhupdatethread(4, key, expire, parseInt(levelData.lid), 'level', tidArr);//批量修改缓存帖子发帖人等级
                }
            }
            yield this.updateUserCache(parseInt(uid), updateUserCache);//更新用户缓存
        }
        return gain;
    }
    return gain;
};

/**
 * @todo 获取等级对应的经验信息
 * @param level 等级 可选，不存在则返回整个列表
 * @returns {*} 等级详情数组
 */

exports.getIntegralInfo = function (level) {
    if (_.v.isIn(level, C.level_action)) {
        return [_C.levelInfo[level - 1]];
    }
    return _C.levelInfo;
};

/**
 * @todo 从经验算等级
 * @param integral
 * @returns {*} 当前等级详情数组
 */

function getLevelfromIntegral(integral) {
    var levelData = this.getIntegralInfo();
    for (var lv in levelData) {
        if (integral <= levelData[lv]['range_h']) {
            return levelData[lv];
        }
    }
    return {};
};
exports.getLevelfromIntegral = getLevelfromIntegral;

/**
 * @todo 由城市代码查城市信息
 * @param citycode 城市代码 可选，不存在则返回整个列表(此时对象格式为：citycode_020 对象 )
 * @returns {*} 城市详情
 */

exports.getCityInfo = function (citycode) {

    if (citycode != undefined) { // 如果存在城市代码参数，则返回此城市
        var retCityInfo = _C.cityInfo['citycode_' + citycode];
        if (retCityInfo == undefined) { // 如果不存在
            return {};
        } else {
            return retCityInfo;
        }
    } else { // 无城市代码参数，则返回全部城市
        return _C.cityInfo;
    }
};

exports.isVest = function (uid) {
    return _.v.isIn(uid, _C.vests_id)
};


function city2code(city) {
    if (city != undefined) {
        for (var i in _C.cityInfo) {
            if (_C.cityInfo[i].city == city) {
                return _C.cityInfo[i].citycode;
            }
        }
    }
    return '';
}
exports.city2code = city2code;

/**
 * @todo 取得达人列表
 * @param talentid 达人代码 可选，不存在则返回整个列表
 * @returns {*} 达人列表
 */

exports.getTalentInfo = function getTalentInfo(talentid) {
    if (talentid != undefined) { // 如果存在城市代码参数，则返回此城市
        var retTalentInfo = _C.talentInfo['talent_' + talentid];
        if (retTalentInfo == undefined) { // 如果不存在
            return {};
        } else {
            return retTalentInfo;
        }
    } else { // 无达人代码参数，则返回全部达人
        return _C.talentInfo;
    }
};

exports.isTalent = function (talentid) {
    return _.v.isIn(talentid, _C.talent_id)
};


// 自动点赞
exports.robotLike = function*() {
    if (C.env != 'production') { // 仅生产环境才执行
        return;
    }

    var rand_int = parseInt(Math.random() * 10);
    if (rand_int != 2) {
        return;
    }
    rand_int = parseInt(Math.random() * 250);
    if (rand_int < 50) {
        rand_int = parseInt(rand_int / 5);
    } else {
        rand_int = rand_int - 50;
    }
    var tids = yield this.list(0, rand_int, 1);
    //if (_C.vests.length==0||_C.vests_id.length) { // 如果缓存不存在,则从数据库中生成
    //  var vest_filter = C.vest_filter.toString();
    //  _C.vests = yield mysql.query('SELECT mv.uid,mu.nickname FROM mh_vest mv JOIN mh_user mu ON mu.uid=mv.uid WHERE mv.status=1 AND mv.uid NOT IN('+vest_filter+')');
    //  for (var i in vests){
    //    _C.vests_id.push(vests[i].uid);
    //  }
    //}

    var vest = _C.vests[parseInt(Math.random() * _C.vests.length)];

    for (var i in tids) {
        var data = {
            fields: {act: 1, tid: tids[i].tid},
            isLogin: {uid: vest.uid, nickname: vest.nickname, groupid: 10, status: true}
        };
        yield commPost.like(this, data);
    }
};

/**
 * @todo 判断是否可申请达人
 * @param userInfo
 * @returns {*} 0 还不可申请 1 可申请 2 正在审批中 3 审批成功 4 审批失败
 */
exports.isAlowerTalent = function*(userInfo) {
    var flag = 0;
    if (typeof userInfo === "object" && userInfo !== null) {
        var userLevel = parseInt(userInfo.level);
        var userThreads = parseInt(userInfo.threads);
        var userDigestthreads = parseInt(userInfo.digestthreads);
        var talentid = parseInt(userInfo.talentid);
        if (userLevel > 2 && userThreads > 10 && userDigestthreads > 1 && talentid == 0) {
            var askLog = yield mysql.query('SELECT * FROM mh_talent_asklog WHERE uid=? ORDER BY alid DESC LIMIT 1', [parseInt(userInfo.uid)]);
            flag = 1;
            if (askLog.length != 0) {
                var askStatus = askLog[0].status;
                if (askStatus == 0) {
                    flag = 2;
                } else if (askStatus == 1) {
                    flag = 3;
                } else if (askStatus == 2) {
                    flag = 4;
                }
            }
        } else if (talentid > 0) {
            flag = 3;
        }
    }
    return flag;
};

function* spotsThreadsId(pagesize, page, rule) {
    return [1472, 1462, 1441];
}

function* spotsTags(pagesize, page, rule) {
    return [
        {
            line: 3,
            type: 2,
            item: {
                tagid: 3,
                tagtype: 1,
                tagtitle: "宝宝健康",
                tagcount: 155,
                pincount: 386,
                pin: false,
                tagurl: 'http://inmm-test.b0.upaiyun.com/tag/000/00/00/03.jpg'
            }
        },
        {
            line: 8,
            type: 2,
            item: {
                tagid: 6,
                tagtype: 1,
                tagtitle: "情感婚姻",
                tagcount: 117,
                pincount: 390,
                pin: false,
                tagurl: 'http://inmm-test.b0.upaiyun.com/tag/000/00/00/06.jpg'
            }
        }
    ];
}

function* spotsUsers(pagesize, page, rule) {
    return [
        {
            line: 3,
            type: 3,
            item: {
                uid: 563,
                nickname: "小洲村[今天星期五]",
                signature: "一二三四五六七八九十分钟，我的好朋友在哪里，在春天里。",
                faceUrl: 'http://inmm-test.b0.upaiyun.com/avatar/000/00/05/63.jpg!jpg300x300',
                friendStatus: true
            }
        },
        {
            line: 12,
            type: 3,
            item: {
                uid: 36,
                nickname: "茱丽叶",
                signature: "网",
                faceUrl: 'http://inmm-test.b0.upaiyun.com/avatar/000/00/00/36.jpg!jpg300x300',
                friendStatus: true
            }
        }
    ];
}

function* spotsTagsDefine(pagesize, page, rule) {
    return [
        {
            "likeusers": [
                {
                    "uid": 835,
                    "faceUrl": "http://inmm-test.b0.upaiyun.com/avatar/000/00/08/35.jpg!jpg75"
                }
            ],
            "post": "ggggiiieee",
            "liketimes": 1,
            "tags": [
                {
                    "tagsid": 1,
                    "tagsType": 1,
                    "tagstitle": "用户标签ddd",
                    "x": 39,
                    "y": 23
                },
                {
                    "tagsid": 1,
                    "tagsType": 2,
                    "tagstitle": "我同学",
                    "x": 39,
                    "y": 36
                }, {
                    "tagsid": 211,
                    "tagsType": 3,
                    "tagstitle": "我的帖子",
                    "x": 39,
                    "y": 49
                }
            ],
            "timeline": 1419229742,
            "uid": 68,
            "nickname": "蚊子11",
            "replies": 1,
            "status": 1,
            "closed": 0,
            "tid": 3624,
            "digest": 0,
            "type": 1,
            "friend": false,
            "fav": false,
            "like": false,
            "faceUrl": "http://inmm-test.b0.upaiyun.com/avatar/000/00/00/68.jpg!jpg75",
            "img": "http://inmm-test.b0.upaiyun.com/img/000/00/19/283.jpg!jpg600"
        }
    ];
}


function* spotsH5(pagesize, page, rule) {
    var tags = [];
    var position = 2;//1发现页 2 首页菜单 3 水印
    var key = C.redisPre.slider_list;
    key = _.str.sprintf(key, position);
    var temp = yield redisCo.EXISTS(key);
    if (temp == 0) {//轮播缓存不存在
        var storeVal = '';
        var sliderData = yield mysql.query("SELECT aid,type,id,begintime,endtime,targeturl,title,cmdStr FROM mh_slider" +
            " WHERE status=1 AND UNIX_TIMESTAMP() BETWEEN begintime AND endtime AND sstype=? ORDER BY sort", [position]);
        if (sliderData && sliderData.length > 0) {
            storeVal = JSON.stringify(sliderData);
        } else {
            storeVal = JSON.stringify([]);
        }
        redisCo.SET(key, storeVal);//把轮播缓存
    }
    sliderData = yield redisCo.GET(key);
    sliderData = JSON.parse(sliderData);
    var timeUnix = timestamp();
    var htmlStr = '';
    if (sliderData && sliderData.length > 0) {
        for (var i in sliderData) {
            if (parseInt(sliderData[i].begintime) <= timeUnix && timeUnix < parseInt(sliderData[i].endtime) + 86400) {
                var aid = sliderData[i].aid.toString();
                var imgUrl = C.upyun.slider_url + '/' + aid + '.jpg';
                var type = sliderData[i].type;
                var id = sliderData[i].id;
                var title = sliderData[i].title;
                var cmdstr=sliderData[i].cmdStr;
                var targetUrl = sliderData[i].targeturl;
                switch (type) {
                    case 1:
                        tags.push({tagsType: type, tagsid: id});
                        htmlStr += '<div class=item onclick=location.href="yueniapp://tagslist/' + id + '"><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        break;
                    case 2:
                        tags.push({tagsType: type, tagsid: id});
                        htmlStr += '<div class=item onclick=location.href="yueniapp://userinfo/' + id + '"><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        break;
                    case 3:
                        tags.push({tagsType: type, tagsid: id});
                        htmlStr += '<div class=item onclick=location.href="yueniapp://thread/' + id + '"><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        break;
                    case 8://8 帖子列表
                        tags.push({tagsType: type});//postlist?cmd=”{act:1,tsoft:1}”&title=”标题
                        htmlStr += '<div class=item onclick=location.href=\'yueniapp://postlist?cmd='+cmdstr+'&title='+title+'\'><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        break;
                    case 9://9百科详情
                        tags.push({tagsType: type});
                        if (id > 0) {
                            htmlStr += '<div class=item onclick=location.href="yueniapp://cijiWiki/' + id + '"><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        } else {
                            htmlStr += '<div class=item onclick=location.href="yueniapp://cijiWiki"><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        }
                        break;
                    case 10://10百科帖子列表
                        tags.push({tagsType: type});
                        if (id > 0) {
                            htmlStr += '<div class=item onclick=location.href="yueniapp://cijiWiki.thread/' + id + '"><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        } else {
                            htmlStr += '<div class=item onclick=location.href="yueniapp://cijiWiki.thread"><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        }
                        break;
                    case 11://11发日记帖
                        tags.push({tagsType: type});
                        htmlStr += '<div class=item onclick=location.href="yueniapp://cijiWiki.diary"><div class=img><img src=' + imgUrl + '></div><span class=title>' + title + '</span></div>';
                        break;
                    default:
                        continue;
                        break;
                }
            }
        }
    }
    var height = 0;
    if (tags.length == 0) {
        return [];
    } else if (tags.length > 0) {
        height = (Math.floor((tags.length - 1) / 4) + 1) * 84;
        height = height + 20;
    }

    return [
        {
            type: 4,
            title: "",
            style: 1,
            height: height,
            h5Type: 2,
            //h5Data: '<!doctype html><html lang=en><head><meta charset=UTF-8><meta name=viewport content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"><title>menu</title><style>*{margin:0;padding:0}.wrapper{width:100%;max-width:640px;min-width:320px;margin:0 auto;overflow:hidden;-webkit-user-select:none;user-select:none}.item{float:left;width:33%;height:100%;box-sizing:border-box;padding-top:19px;color:#444;font-size:12px;text-align:center;}.item a{text-decoration:none}.img{height:37px;width:100%;}.img img{width:37px;height:37px;display:inline-block;vertical-align:middle}.title{margin-left:4px;display:inline-block;vertical-align:middle;}</style></head><body><div class=wrapper>' +
            h5Data:'<!doctype html><html lang=en><head><meta charset=UTF-8><meta name=viewport content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no\"><title>menu</title><style>*{margin:0;padding:0}.wrapper{width:100%;max-width:640px;min-width:320px;margin:0 auto;overflow:hidden;-webkit-user-select:none;user-select:none}.item{float:left;width:25%;height:100%;box-sizing:border-box;padding:15px 0 0 0;color:#444;font-size:12px;text-align:center;}.item a{text-decoration:none}.img{height:47px;width:100%;}.img img{width:47px;height:47px;display:inline-block;vertical-align:middle}.title{margin:8px 0 0 4px;display:inline-block;vertical-align:middle;}</style></head><body><div class=wrapper>'+
            htmlStr +
            '</div></body></html>'
        }
    ];
}
/**
 * @todo 取得首页菜单
 * @returns {{type: number, title: string, tags: Array}[]}
 */
function* spotsMenu() {
    var tags = [];
    var position = 2;
    var key = C.redisPre.slider_list;
    key = _.str.sprintf(key, position);
    var temp = yield redisCo.EXISTS(key);
    if (temp == 0) {//轮播缓存不存在
        var storeVal = '';
        var sliderData = yield mysql.query("SELECT aid,type,id,begintime,endtime,targeturl,title FROM mh_slider WHERE status=1 AND UNIX_TIMESTAMP() BETWEEN begintime AND endtime AND sstype=? ORDER BY sort", [position]);
        if (sliderData.length > 0) {
            storeVal = JSON.stringify(sliderData);
        } else {
            storeVal = JSON.stringify([]);
        }
        redisCo.SET(key, storeVal);//把轮播缓存
    }
    sliderData = yield redisCo.GET(key);
    sliderData = JSON.parse(sliderData);
    var timeUnix = timestamp();
    if (sliderData.length > 0) {
        for (var i in sliderData) {
            if (parseInt(sliderData[i].begintime) <= timeUnix && timeUnix < parseInt(sliderData[i].endtime) + 86400) {
                var aid = sliderData[i].aid.toString();
                var imgUrl = C.upyun.slider_url + '/' + aid + '.jpg';
//        var imgUrl=this.generateSliderUrl(sliderData[i].aid);
                var type = sliderData[i].type;
                var id = sliderData[i].id;
                var title = sliderData[i].title;
                var targetUrl = sliderData[i].targeturl;
                tags.push({
                    tagsType: type,
                    tagsid: id,
                    tagstitle: title,
                    tagurl: imgUrl,
                    targeturl: sliderData[i].targeturl
                });
            }
        }
    }
    return [
        {
            type: 5,
            title: '首页菜单',
            tags: tags
        }
    ];
}


/* ip地址查城市 淘宝接口获取
 return {
 “citycode”: “020”,
 "country": "中国",
 "country_id": "CN",
 "area": "华南",
 "area_id": "800000",
 "region": "广东省",
 "region_id": "440000",
 "city": "佛山",
 "city_id": "440600",
 "county": "",
 "county_id": "-1",
 "isp": "电信",
 "isp_id": "100017",
 "ip": "14.215.31.77"
 }
 */
exports.ip2city = function (ip, cb) {
    var ip_start = ip.lastIndexOf(':');
    ip = ip.slice(ip_start >= 0 ? ip_start + 1 : 0);
    console.log(ip);
    if (ip.slice(0, 8) == '192.168.') {
        cb('Local', '');
    } else {
        var options = {
            url: 'http://ip.taobao.com/service/getIpInfo.php?ip=' + ip
        };
        async_request.get(options, function (error, response, body) {
            if (error) {
                if (typeof cb === 'function') {
                    cb(error, '');
                } else {
                    console.error('ip2city ERROR:', error);
                }
            }
            var cityInfo = isJson(body);
            if (cityInfo.code == 0) { // 有效数据
                var city = cityInfo.data.city.slice(0, -1);
                var citycode = city2code(city);
                if (typeof cb === 'function') {
                    cb(error, citycode);
                }
            }
        });
    }
};

// 执行读取 _C 参数
get_mysql_config();


// 读取 _C 参数
function get_mysql_config() {


    // 获取马甲列表
    // 如果缓存不存在,则从数据库中生成
    if (_C.vests.length == 0 || _C.vests_id.length == 0) {
        var vest_filter = C.vest_filter.toString();
        mysql.query('SELECT mv.uid,mu.nickname FROM mh_vest mv JOIN mh_user mu ON mu.uid=mv.uid WHERE mv.status=1 AND mv.uid NOT IN(' + vest_filter + ')',
            function (error, results) {
                if (error) {
                    console.log("ERROR: 获取马甲列表失败 " + error.message);
                    return;
                }
                _C.vests = results;
                for (var i in _C.vests) {
                    _C.vests_id.push(_C.vests[i].uid);
                }
                for (var j in C.vest_filter) {
                    _C.vests_id.push(C.vest_filter[j]);
                }
            });
    }

    // 获取等级经验列表
    // 如果缓存不存在,则从数据库中生成
    if (_C.levelInfo.length == 0) { // 如果缓存不存在,则从数据库中生成
        //var levelData=yield mysql.query('SELECT * FROM mh_level ORDER BY lid');
        mysql.query('SELECT * FROM mh_level ORDER BY lid',
            function (error, results) {
                if (error) {
                    console.log("ERROR: 获取等级列表失败 " + error.message);
                    return;
                }
                if (results) {
                    for (var lv in results) {
                        results[lv].reward = [0];
                        for (var reward in C.level_action) {
                            results[lv].reward.push(results[lv]['reward' + C.level_action[reward]]);
                            delete results[lv]['reward' + C.level_action[reward]];
                        }
                    }
                }
                _C.levelInfo = results;
            });
    }


    // 获取城市代码列表
    // 如果缓存不存在,则从数据库中生成
    if (_C.cityInfo.length == 0) { // 如果缓存不存在,则从数据库中生成
        //var cityData = yield mysql.query('SELECT * FROM mh_district ORDER BY id');
        mysql.query('SELECT * FROM mh_district ORDER BY id',
            function (error, results) {
                if (error) {
                    console.log("ERROR: 获取城市列表失败 " + error.message);
                    return;
                }
                var tmpCityInfo = {};
                var ccode;
                if (results) {
                    for (var id in results) {
                        ccode = 'citycode_' + results[id]['citycode'];
                        tmpCityInfo[ccode] = results[id];
                        delete tmpCityInfo[ccode].id;
                    }
                    _C.cityInfo = tmpCityInfo;
                }
            }
        );
    }


    // 获取达人列表
    // 如果缓存不存在,则从数据库中生成
    if (_C.talentInfo.length == 0 || _C.talent_id.length == 0) { // 如果缓存不存在,则从数据库中生成
        //var cityData = yield mysql.query('SELECT * FROM mh_district ORDER BY id');
        mysql.query('SELECT * FROM mh_talent ORDER BY talentid',
            function (error, results) {
                if (error) {
                    console.log("ERROR: 获取达人列表失败 " + error.message);
                    return;
                }
                var tmpTalentInfo = {};
                var tmpTalent_id = [];
                var ccode;
                if (results) {
                    for (var id in results) {
                        ccode = 'talent_' + results[id]['talentid'];
                        tmpTalentInfo[ccode] = results[id];
                        tmpTalent_id.push(results[id]['talentid']);
                    }
                    _C.talentInfo = tmpTalentInfo;
                    _C.talent_id = tmpTalent_id;
                }
            }
        );
    }

    // 获取模块列表
    // 如果缓存不存在,则从原始数据中生成
    if (_.isEmpty(_C.sliderInfo)) { // 如果缓存不存在,则从数据库中生成
        //var cityData = yield mysql.query('SELECT * FROM mh_district ORDER BY id');

        let ccode;
        for (var id in C.slider_type) {
            ccode = 'stid_' + C.slider_type[id]['stid'];
            _C.sliderInfo[ccode] = C.slider_type[id];
        }
        //_C.sliderInfo = tmpsliderInfo;
    }


}

/*@ 取轮播组
 @ param array []
 @ return {}
 */

exports.getSliderGroup = function*(arr) {
    let retData = [];
    let sliderInfo = {};
    let data = {};
    let obj = {};
    if (_.isArray(arr)) {
        for (var i in arr) {
            sliderInfo = exports.getSliderInfo(arr[i]);
            obj = sliderInfo.info;
            //obj['type'] = sliderInfo.typeid;
            obj['stid'] = arr[i];
            data = yield exports.getSliderNew(obj);
            if (data) {
                retData.push(data);
            }
        }
    }
    return retData;
};

/**
 * @ 取轮播图
 * @param fields  //{type:1,stid:1 title: ''}
 * @returns {*}
 */
exports.getSliderNew = function*(fields) {
    let retData = {};
    let sliderInfo = exports.getSliderInfo(fields.stid);
    if (sliderInfo.typeid == 1) { // 新发现页轮播
        var data = yield commPost.getSlider({I: {act: 1, typeid: 1, position: fields.stid,app_ver_arr: fields.app_ver_arr}});
        if (data.status == 200) {
            retData.type = 5; // 轮播图
            var slider = C.slider_type;
            for (var i in slider) {
                if (slider[i]['stid'] == 7) {
                    retData.android_height = slider[i]['height'] / 2;
                    retData.ios_height = slider[i]['height'] * 4 / 9;
                    break;
                }
            }

            for (var i in data.result.items) {
                delete data.result.items[i]['aid'];
            }

            if (fields.title != '') { // 未传标题时，设置默认标题
                retData.title = fields.title || '发现页轮播图';
                if (fields.more && fields.more > 0) { // 有更多选项
                    retData.more = fields.more;
                }
            }
            retData.items = data.result.items;
        }

        // 新发现页推荐标签
    } else if (sliderInfo.typeid == 5) {
        //and ms.begintime<=UNIX_TIMESTAMP() and (ms.endtime+86400)>=UNIX_TIMESTAMP()
        var tags = yield mysql.query('SELECT mt.tagid,mt.tagtype,mt.tagtitle,mt.tagimg,mt.tagdesc FROM mh_tags mt ' +
            'JOIN mh_slider ms ON mt.tagid = ms.id WHERE ms.status=1 and ms.sstype=? ORDER BY sort', [fields.stid]);

        if (tags) {
            for (var i in tags) {
                tags[i]['tagurl'] = this.generateTagUrl(tags[i]['tagimg'], tags[i]['tagid']);
                tags[i]['tagnew'] = 0;
                delete tags[i]['tagimg'];
            }

            retData.type = 6; // 标签

            if (fields.title != '') { // 未传标题时，设置默认标题
                retData.title = fields.title || '推荐内容';
                if (fields.more && fields.more > 0) { // 有更多选项
                    retData.more = fields.more;
                    retData.cmd = fields.cmd;
                }
            }

            retData.items = tags;
        } else {
            retData = {};
        }
    } else if (sliderInfo.typeid == 7) {//发现页专题
        var limit = '';
        if (fields.limit && parseInt(fields.limit) > 0) {
            limit = 'LIMIT ' + parseInt(fields.limit);
        }
        var tsliderData = yield mysql.query('SELECT ms.aid,ms.type,ms.id,ms.timeline,ms.title,ms.cmdStr FROM mh_slider ms WHERE ms.status=1 AND ms.sstype=? ORDER BY sort ' + limit, [fields.stid]);
        var sliderData = [];
        if (tsliderData.length > 0) {
            for (let i in tsliderData) {
                var type = tsliderData[i].type;
                var imgUrl = this.generateSliderUrl(tsliderData[i].aid);
                var id = tsliderData[i].id;
                var title = tsliderData[i].title;
                var cmdStr = tsliderData[i].cmdStr;
                switch (type) {
                    case 1://标签
                        sliderData.push({imgUrl: imgUrl, type: type, tagid: id, title: title});
                        break;
                    case 3://帖子
                        sliderData.push({imgUrl: imgUrl, type: type, tid: id, title: title});
                        break;
                    case 6://水印标签
                        sliderData.push({imgUrl: imgUrl, type: type, tagid: id, title: title});
                        break;
                    case 8://帖子列表
                        sliderData.push({imgUrl: imgUrl, type: type, cmd: cmdStr, title: title});
                        break;
                }
            }
            retData.type = 8; // 新专题
            if (fields.stid == 12) {
                retData.type = 7; // 旧专题
            }

            if (fields.title != '') { // 未传标题时，设置默认标题
                retData.title = fields.title || '专题';
                if (fields.more && fields.more > 0) { // 有更多选项
                    retData.more = fields.more;
                    retData.cmd = sliderInfo.info.cmd;
                    retData.moreTitle = fields.moreTitle;
                }
            }

            retData.items = sliderData;
        } else {
            retData = {};
        }
    } else if (sliderInfo.typeid == 9) {//发现页类别专题
        var categorys = yield mysql.query('SELECT cid,name,detail,categoryimg from mh_thread_category ' +
            'where status=1 and pcid IN( ' +
            'select cid from mh_thread_category mtc where mtc.name=? and pcid=0 and ctype=0) ORDER BY sort', [fields.title]);
        if (categorys) {
            for (var i in categorys) {
                //categorys[i]['categoryurl'] = this.generateTagUrl(categorys[i]['categoryimg'], categorys[i]['cid']);
                categorys[i]['categorynew'] = 0;
                delete categorys[i]['tagimg'];
            }
            retData.type = 9; // 帖子类别
            if (fields.title != '') { // 未传标题时，设置默认标题
                retData.title = fields.title || '推荐内容';
                if (fields.more && fields.more > 0) { // 有更多选项
                    retData.more = fields.more;
                    retData.cmd = fields.cmd;
                }
            }

            retData.items = categorys;
        } else {
            retData = {};
        }
    }
    return retData;
};
/**
 * @todo 取得最近申请成功的达人
 * @param fields(type 类型id  title 抬头 more )
 */
exports.getLatestTalent = function*(fields) {
    var returnData = {};
    var latestTalent = yield mysql.query('SELECT mta.uid FROM mh_talent_asklog mta WHERE mta.`status`=1 ORDER BY mta.apptime DESC LIMIT 10');
    if (latestTalent.length != 0) {
        returnData.type = fields.type || 3;
        if (!(fields.title == undefined || fields.title == '')) {
            returnData.title = fields.title || '社区达人';
        }
        if (fields.more && fields.more > 0) { // 有更多选项
            returnData.more = fields.more;
        }
        returnData.items = [];
        for (var i in latestTalent) {
            var userData = yield this.returnUserInfo(latestTalent[i].uid);
            userData = userData[0];
            var face = this.generateFaceUrl(parseInt(userData.face), latestTalent[i].uid);
            var talentLevel = userData.talent_level == undefined ? 0 : parseInt(userData.talent_level);
            returnData.items.push({
                "uid": parseInt(userData.uid),
                "nickname": userData.nickname,
                "face": face,
                vip: parseInt(userData.vip),
                "talent_level": talentLevel
            });
        }
    }
    return returnData;
};

/**
 * @todo 返回模块列表
 * @param stid 模块代号 可选，不存在则返回整个列表(此时对象格式为：stid_020 对象 )
 * @returns {*} 城市详情
 */

exports.getSliderInfo = function (stid) {
    if (stid != undefined) { // 如果存在城市代码参数，则返回此城市
        var retSliderInfo = _C.sliderInfo['stid_' + stid];
        if (retSliderInfo == undefined) { // 如果不存在
            return {};
        } else {
            return retSliderInfo;
        }
    } else { // 无模块代号参数，则返回全部
        return _C.sliderInfo;
    }
};


/**
 * @todo 返回板块tagid数组 2层
 * @param stid 模块代号 可选，不存在则返回整个列表(此时对象格式为：stid_020 对象 )
 * @returns {*}
 */

exports.getBrondTagid = function* () {
    let brond = [];
    let retBrondInfo = yield redisCo.get(C.redisPre.env_brond_tagid);
    if (retBrondInfo != null && retBrondInfo.length > 0) { // 存在
        brond = isJson(retBrondInfo);
    } else { // 不存在
        let tags = C.slider_brond_tags.join();
        let retData = yield mysql.query('SELECT id FROM mh_slider WHERE status =1 and type in (1,4,6,99) and sstype in (' + tags + ') and id>0 order by sstype,sort');
        if (retData) {
            for (let i in retData) {
                brond.push(retData[i]['id']);
            }
        }
        tags = _.uniq(brond);
        retData = yield mysql.query('SELECT tagid FROM mh_tags WHERE fid in (' + tags.join() + ')');
        if (retData) {
            for (let i in retData) {
                brond.push(retData[i]['tagid']);
            }
        }
        brond = _.uniq(brond);
        yield redisCo.del(C.redisPre.env_brond_tagid);
        yield redisCo.set(C.redisPre.env_brond_tagid, JSON.stringify(brond));
    }
    return brond;
};


/*
 @todo 保存标签地理位置信息
 @param {poiid,name,tagid,longitude,latitude}
 */
exports.savePoi2Mongo = function (poi) {
    var poiInfo = new exports.poiModel;
    poiInfo._id = 'YN_poiid_' + poi.poiid;
    poiInfo.poiName = poi.name;
    poiInfo.tagid = poi.tagid;
    poiInfo.loc = [poi.longitude, poi.latitude];
    poiInfo.save();
};

/*
 @todo 保存用户地理位置信息
 @param {poiid,longitude,latitude}
 */
exports.saveUser2Mongo = function (user) {
    var userInfo = new exports.userModel;
    userInfo._id = 'YN_userid_' + user.uid;
    userInfo.timeline = this.timestamp();
    userInfo.loc = [user.longitude, user.latitude];
    userInfo.save();
};


/*
 @todo 取某用户标签的原帖子数量
 @param {uid:123,tagid:[1,2,3,4]}
 @return {tagid_1:3,tagid_2:3,tagid_3:0}
 */
exports.getUserTagnew = function *(obj) {
    let retData = {};
    if (obj['uid'] > 0 && _.isArray(obj.tagid) && obj.tagid.length > 0) {
        var data = yield mysql.query('SELECT mt.tagid, (mt.tagcount - IFNULL(mut.tagcount,0)) as num FROM mh_tags mt LEFT JOIN mh_user_tagcount mut ON (mut.uid=? and mut.tagid=mt.tagid) WHERE mt.tagid in (' + obj.tagid.join() + ')', [obj['uid']]);
    }
    for (let i in data) {
        retData['tagid_' + data[i]['tagid']] = data[i]['num'] > 1000 ? 1000 : (data[i]['num'] < 0 ? 0 : data[i]['num']);
    }
    return retData;
};

/*
 @todo 取某用户关于帖子类别的原帖子数量
 @param {uid:123,cid:[1,2,3,4]}
 @return {cid_1:3,cid_2:3,cid_3:0}

 exports.getUserCategoryNew=function *(obj){
 let retData = {};
 if (obj['uid']>0 && _.isArray(obj.tagid) && obj.tagid.length>0){
 var data = yield mysql.query('select mtc.cid,(mtc.threads-IFNULL(muc.threadcount,0)) as num '+
 'from mh_thread_category mtc LEFT JOIN mh_user_categorycount muc on mtc.cid=muc.cid and muc.uid=? '+
 'where mtc.cid in ('+obj.tagid.join()+')',[obj['uid']]);
 }
 for (let i in data){
 retData['cid'+data[i]['cid']] = data[i]['num']>1000?1000:(data[i]['num']<0?0:data[i]['num']);
 }
 return retData;
 };
 */

exports.upyun_purge = function (arr) {
    //let up_purge = thunkify(upyun.purge);
    //return yield up_purge(arr);
    return function (fn) {
        upyun.purge(arr, fn);
    }
};

/*
 @todo 返回是否需要审核
 @return 0 无需审核，1 需审核
 */
exports.check_post = function *() {
    let check_post_status = yield redisCo.get(C.redisPre.check_post);
    if (check_post_status == null) {
        check_post_status = 0; // 0 无需审核，1 需审核
        let check_mysql = yield mysql.queryOne('SELECT setting FROM mh_config WHERE name="check_post"');
        if (check_mysql && check_mysql['setting'] == 1)
            check_post_status = 1;
        redisCo.set(C.redisPre.check_post, check_post_status);
    }
    return parseInt(check_post_status);
};


exports.getActivity = function*(actid) {
    let activity = {
        actid: actid,
        acttype: 0,
        acttitle: '',
        wareid: 0,
        begintime: null,
        endtime: null,
        detail: '',
        validbegintime: null,
        validendtime: null,
        status: 0,
        imageurl: '',
        shareurl: '',
        steps: []
    };
    let result = yield mysql.queryOne('select * from mh_activity where actid=?', [actid]);
    if (result) {
        let stepResult = yield mysql.query('select * from mh_activity_step where actid=? order by sorder', [actid]);
        let stepArray = [];
        if (stepResult && stepResult.length > 0) {
            for (var i in stepResult) {
                let stepEntity = new mActivityStep.activityStep(stepResult[i]);
                stepArray.push(stepEntity.stepInfo);
            }
        }
        activity['acttype'] = result['acttype'];
        activity['acttitle'] = result['acttitle'];
        activity['wareid'] = result['wareid'];
        activity['begintime'] = result['begintime'];
        activity['endtime'] = result['endtime'];
        activity['detail'] = result['detail'];
        activity['validbegintime'] = result['validbegintime'];
        activity['validendtime'] = result['validendtime'];
        activity['status'] = result['status'];
        activity['imageurl'] = result['imageurl'];
        activity['shareurl'] = result['shareurl'];
        activity['steps'] = stepArray;
    } else {//活动不存在时，将actid设为0
        activity['actid'] = 0;
    }
    return activity;
}

exports.getRegionArray = function*(regionid) {
    let region = {
        province_id: 0,
        province: '',
        city_id: 0,
        city: '',
        district_id: 0,
        district: '',
        street_id: 0,
        street: ''
    };
    while (region['province_id'] == 0 && regionid > 0) {
        let result = yield mysql.queryOne('SELECT * FROM mh_region mhr WHERE mhr.region_id=?', [regionid]);
        if (result) {
            switch (result['region_type']) {
                case 1: //省
                    region['province_id'] = result['region_id'];
                    region['province'] = result['region_name'];
                    regionid = 0;
                    break;
                case 2: //市
                    region['city_id'] = result['region_id'];
                    region['city'] = result['region_name'];
                    regionid = result['parent_id'];
                    break;
                case 3: //区
                    region['district_id'] = result['region_id'];
                    region['district'] = result['region_name'];
                    regionid = result['parent_id'];
                    break;
                case 4: //街
                    region['street_id'] = result['region_id'];
                    region['street'] = result['region_name'];
                    regionid = result['parent_id'];
                    break;
                default:
                    regionid = 0;
            }
        }
    }
    return region;
};

/*
 @todo 判断用户是否已经绑定手机
 @return  true 已经版定；false：未绑定
 */
exports.userMobile = function *(uid) {
    let userMobile = yield MUsers.getUser('uid,mobile', 'LENGTH(mobile)=11 and uid=?', [uid]);
    return userMobile;
};

/*
 @todo 查询用户活动状态查询
 @return  retcode 0:活动不存在; 1:活动未开始；2：兑换活动已结束；3：领取验证码时间已过；4：未登录；
 5：需要版定手机号码；6：可领取验证码；7：已经兑换过礼品；8：未到兑换开始时间；9：可到店领取
 */
exports.get_userActivityState = function*(Env) {
    let fields = Env.I;
    //let loginStatus = yield this.isLogin(Env);
    let loginStatus = fields.loginStatus;
    let uid = loginStatus.uid;
    let UserMobileInfo = {};
    let actid = fields.actid || 0;
    let activity = yield this.getActivity(actid);
    let activityEntity = new mActivity.marketActivity(activity);
    let actDateData = yield activityEntity.checkDate(activityEntity.actInfo);
    let goNexStep = true;
    let result = {};
    if (activityEntity.actInfo) {
        result.imgurl = C.upyun.activity_img_url + activityEntity.actInfo['imageurl'];
        result.shareurl = C.upyun.activity_img_url + activityEntity.actInfo['shareurl'];
        result.title = activityEntity.actInfo['acttitle'];
        result.actid = activityEntity.actInfo['actid'];
        result.acttype = activityEntity.actInfo['acttype'];
        result.begintime = activityEntity.actInfo['begintime'];
        result.endtime = activityEntity.actInfo['endtime'];
        result.validbegintime = activityEntity.actInfo['validbegintime'];
        result.validendtime = activityEntity.actInfo['validendtime'];
        result.detail = _.str.unescapeHTML(activityEntity.actInfo['detail']);
        result.wareid = activityEntity.actInfo['wareid'];
    }
    let currentDate = this.timestamp();
    //当前时间范围不符合
    if (actDateData.data.retcode > -1) {
        goNexStep = false;
        result.retcode = actDateData.data.retcode;
    }
    //判断是否登录
    if (goNexStep) {
        if (!loginStatus.status) {
            goNexStep = false;
            result.retcode = 4;
        }
        else {
            UserMobileInfo = yield this.userMobile(uid);
        }
    }
    //判断用户是否接收过验证码以及是否已经领取礼品
    if (goNexStep) {
        let userActicityData = yield mysql.queryOne('select mo.uid,ma.acttitle,ma.actid,moc.mobile,moc.captcha,moc.ocid,moc.receive,ma.endtime,ma.validbegintime,ma.shareurl,ma.imageurl,ma.acttype' +
            ' from mh_activity ma left JOIN mh_order mo on ma.actid=mo.actid LEFT JOIN mh_order_captcha moc on moc.orderid=mo.orderid where mo.uid=? and ma.actid=? and LENGTH(moc.captcha)>0', [uid, actid]);
        if (!userActicityData || !userActicityData['captcha']) {//没有领取验证码
            let endTime = parseInt(new Date(new Date(activityEntity.actInfo['endtime'] * 1000).format('yyyy-MM-dd') + ' 0:0:0 CST+800').getTime() / 1000) + 86400;
            if (currentDate > endTime) {
                result.retcode = 3;
                goNexStep = false;
            } else {
                //判断用户是否绑定手机
                if (UserMobileInfo.length == 0) {
                    goNexStep = false;
                    result.retcode = 5;
                }
                else {
                    goNexStep = false;
                    result.retcode = 6;
                    result.mobile = UserMobileInfo[0]['mobile'];
                }
            }
        } else {
            result.mobile = userActicityData['mobile'];
            result.captcha = userActicityData['captcha'];
        }
        if (goNexStep && userActicityData) {
            if (userActicityData['receive'] && userActicityData['receive'] == 1) {
                goNexStep = false;
                result.retcode = 7;
            }
        }
        if (goNexStep && userActicityData) {
            let validBeginTime = parseInt(new Date(new Date(activityEntity.actInfo['validbegintime'] * 1000).format('yyyy-MM-dd') + ' 0:0:0 CST+800').getTime() / 1000);
            if (currentDate < validBeginTime) {
                goNexStep = false;
                result.retcode = 8;
            }
        }
        if (goNexStep && userActicityData) {
            result.captchaid = userActicityData['ocid'];
            result.retcode = 9;
        }
    }
    return result;
};

/*
 根据传入的活动步骤id，userid，actid，还原步骤逻辑并验证其是否通过
 */
exports.get_userActivityStep = function*(Env) {
    let fields = Env.I;
    //let loginStatus = yield this.isLogin(Env);
    let loginStatus = fields.loginStatus;
    let uid = loginStatus.uid;
    let actid = fields.actid || 0;
    let activity = yield this.getActivity(actid);
    let activityEntity = new mActivity.marketActivity(activity);
    let actDateData = yield activityEntity.checkDate(activityEntity.actInfo);
    let goNexStep = true;
    let result = {};
    result.data = activityEntity;
    if (actDateData.data.retcode > -1) {
        goNexStep = false;
        result.retcode = actDateData.data.retcode;
        result.stepMsg = actDateData.data.retmsg;
    }
    if (goNexStep) {//活动正在生效时间内
        let activitySteps = activityEntity.actInfo.steps;
        let stepResult = {};
        for (var i in activitySteps) {
            let mStep = new mActivityStep.activityStep(activitySteps[i]).stepInfo;
            mStep.begintime = activityEntity.actInfo['begintime'];
            mStep.endtime = activityEntity.actInfo['endtime'];
            mStep.validbegintime = activityEntity.actInfo['validbegintime'];
            mStep.validendtime = activityEntity.actInfo['validendtime'];
            stepResult = yield this.init_userActivityStep(mStep, uid);
            result.stepMsg = stepResult.stepMsg;
            if (!stepResult.goNexStep) {
                break;
            }
        }
    }
    return result;
}

exports.init_MongoData = function*(item, type) {
    ;
    if (type == 'wareList') {
        for (let i in item.shops) {
            delete item.shops[i].shopInfo;
            delete item.shops[i]._id;
            for (let j in item.shops[i].district) {
                delete item.shops[i].district[j]._id;
            }
        }
    } else {

    }
    return item;
}

exports.init_userActivityStep = function*(mStep, uid) {
    let ret = {goNexStep: false, stepMsg: 'success'};
    let strSQL = '';
    switch (mStep['entity'].toString()) {
        case 'mh_user'://用户表字段校验
            strSQL = _.str.join(" ", "select 1 from mh_user", "where uid=", uid.toString(), "and", mStep['rule']);
            break;
        case 'mh_thread'://帖子表相关字段校验
            strSQL = _.str.join(" ", "select 1 from mh_thread", "where uid=", uid.toString(), "and", mStep['rule'], "and timeline BETWEEN", mStep['begintime'], "and", mStep['endtime']);
            break;
        case 'mh_user_info'://用户信息相关字段校验
            strSQL = _.str.join(" ", "select 1 from mh_user_info", "where uid=", uid.toString(), "and", mStep['rule']);
            break;
        case 'mh_thread_tags'://帖子标签表相关字段
            strSQL = _.str.join(" ", "select 1 from mh_thread mt inner JOIN mh_thread_tags mtt on mt.tid=mtt.tid where mt.timeline BETWEEN", mStep['begintime'], "and", mStep['endtime'], "and mt.uid=", uid.toString(), "and", mStep['rule'].replace("mh_thread_tags", "mtt"));
            break;
        case 'success'://已经成功参与活动
            ret.stepMsg = mStep['errormsg'];
            return ret;
    }
    let result = yield mysql.query(strSQL);
    if (result && result.length > 0) {
        ret.goNexStep = true;
    } else {
        ret.stepMsg = mStep['errormsg'];
    }
    return ret;
};

/**
 * 检查登录用户是否已经消费过项目【美容日记】
 * @param orderid order id
 * @param wareid  商品id
 * @param isManager 是否管理员
 * return 订单详情
 */
exports.orderData = function*(uid,orderid, wareid, isManager) {
    let returnData = {success: false};//返回订单信息
    let orderData = {hasConsume:true,didNotWriteDaily:true};
    if (!isManager) {
        //普通登录用户检查是否有消费
        let orderRecord = yield o2oF.o2oGetOrderDetailByOrderId({act: 1, orderid: orderid});
        if (parseInt(orderRecord['result']['error']) == 1 || orderRecord.status == 400){
            return returnData;
        }else {
            //check whether uid has consume and did not write any daily based on current order
            //if (parseInt(orderRecord['result']['has_consumed_number']) == 0 ) {
            //    orderData.hasConsume=false;
            //}
            //if(parseInt(orderRecord['result']['daily_thread_id']) > 0){
            //    orderData.didNotWriteDaily=false;
            //}
            //if(orderData.hasConsume&&orderData.didNotWriteDaily)
            //{
                returnData.success = true;
                orderData = orderRecord['result'];
                wareid = orderData.wareid;
            //}
        }
    }

    let o2o_supplierData = yield o2oF.o2oGetWareDetailByWareId(wareid);
    //检查商品和商家是否匹配
    if (isManager&&!_.isEmpty(o2o_supplierData['wareName']))
    {
        returnData.success = true;
        orderData = {orderid: 0, consume_date: this.timestamp(), quantity: 1};
        orderData.wareid = wareid;
    }
    orderData.vendorid = o2o_supplierData['vendorid'];
    orderData.wareName = o2o_supplierData['wareName'];
    orderData.categoryId = o2o_supplierData['categoryCode'];
    orderData.categoryName = o2o_supplierData['categoryName'];

    returnData.orderData = orderData;
    return returnData;
};


/**
 * 根据post内容自动分类
 * @param opts
 * @returns {Function}
 * yield后的结果为[{...}，{...},{...}]
 */
exports.autoCate= function*(post){
    var querystring =require('querystring');
    var postData = querystring.stringify({
        'act' : 1,
        'post':post
    });
    var opts = {
        postData:postData,
        hostname: C.autocate.host,
        port: C.autocate.port,
        path: C.autocate.path,
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Content-Length': postData.length
        }
    };
    var http =require('http');
    return new Promise(function(fulfil,reject){
        var req = http.request(opts,function(res) {
            res.setEncoding('utf8');
            var data ='';
            res.on('data', function (chunk) {
                data += chunk;
            });
            res.on('end',function(){
                data = JSON.parse(data);
                fulfil(data.result.item);
            });
        });
        req.on('error', function(e) {
            console.log('problem with request: ',e);
            reject(e);
        });
        req.write(opts.postData);
        req.end();
    }).then(function(data){
            return data;
        },function(err){
            var arr=[];
            arr.push([C.autocate.default_cate.cid,1]);
            return arr;
        });
}


/**
 * 帖子图片，视频或用户头像点击记录
 * @param type  类型：int，操作类型 1 点击帖子图像，2 点击帖子视频，3 点击个人头像
 * @param uid 类型：int,当前操作者，登录或未登录用户
 * @param id  类型：int,被点击对象id,即帖子id,回帖id或用户id
 * @param device_id 类型；str,当前操作者手机设备信息,包括device_type,device_id
 * @param mark  点击场景来源 验证后的mark
 */
exports.writeMediaviewLog = function*(type,uid,id,device_id,mark){
    let returnData = {success: false,info:''};//返回操作信息
    if(!_.v.isIn(type,[1,2,3])){
        returnData.info='传递的参数错误';
        return returnData;
    }
    if(type==3){
        //检验用户是否合法
        let userInfo = yield this.returnUserInfo(id);
        if(userInfo.length==0){
            returnData.info='传递的参数错误';
            return returnData;
        }
        let logInfo= yield mysql.query('INSERT INTO mh_thread_mediaViewlog(uid,type,id,timeline,device_id,mark) VALUES(?,?,?,UNIX_TIMESTAMP(),?,?)',[uid,type,id,device_id,mark]);
        if(logInfo.affectedRows==0){
            returnData.info='记录操作失败';
            return returnData;
        }
        yield mysql.query('UPDATE mh_user_info SET avatarviews=avatarviews+1 WHERE uid=?',[id]);
        returnData.success=true;
    }else{
        //当id为帖子tid的情形,验证tid合法性[有TH且无P]
        if(_.v.contains(mark,'TH') && !/[^A-Z]P\d+/.test(mark)){
            if(id>0){
                //检查传递的帖子是否合法,分tid或pid来校验
                let threadInfo = yield this.returnThreadInfo(id);
                if(threadInfo.length==0){
                    returnData.info='传递的参数错误';
                    return returnData;
                }
                //写入mediaViewLog记录
                let logInfo= yield mysql.query('INSERT INTO mh_thread_mediaViewlog(uid,type,id,timeline,device_id,mark) VALUES(?,?,?,UNIX_TIMESTAMP(),?,?)',[uid,type,id,device_id,mark]);
                if(logInfo.affectedRows==0){
                    returnData.info='记录操作失败';
                    return returnData;
                }
                //写入关联计数
                if(type==2){
                    yield mysql.query('UPDATE mh_thread SET videoviews=videoviews+1 WHERE tid=?',[id]);
                }else{
                    yield mysql.query('UPDATE mh_thread SET imgviews=imgviews+1 WHERE tid=?',[id]);
                }
            }
        }else{
            //写入mediaViewLog记录,id可能为pid,也肯为0的情形，此时没有关联操作
            let logInfo= yield mysql.query('INSERT INTO mh_thread_mediaViewlog(uid,type,id,timeline,device_id,mark) VALUES(?,?,?,UNIX_TIMESTAMP(),?,?)',[uid,type,id,device_id,mark]);
            if(logInfo.affectedRows==0){
                returnData.info='记录操作失败';
                return returnData;
            }
        }
        returnData.success=true;
    }
    return returnData;
}

//发帖，回帖检查传入的post内容是否是广告（根据自动分类方法分类所得）
exports.checkCid= function *(data){
    let cid = data.cid || -1;
    if(parseInt(cid)==-1){
        cid=C.threadCategory.default_category;
    }
    let post = _s.trim(data.post) || '';
    let isSPAM = data.isSPAM || 0;
    let default_cid = C.threadCategory.default_category;
    let ret = {
        cid: 0,
        cid_display: 0,
        SPAM: 0,
        ctype:0 //分类方式，0为用户分类，1人工分类，2机器分类
    };
    if(post==''){
        ret.cid = cid == -1 ? default_cid : cid;
        ret.cid_display = cid == -1 ? default_cid : cid;
        ret.ctype = cid == -1 ? 2 : 0;
        return ret;
    }
    let SPAM_cid = C.threadCategory.SPAM_unique_category;
    if (isSPAM > 0) { // 是广告、微商等类型，统一归到广告类
        ret.cid = SPAM_cid;
        ret.cid_display = cid == -1 ? default_cid : cid;
        ret.SPAM = 1;
        return ret;
    }
    // 机器自动分类识别
    let auto_cid_array = yield this.autoCate(post);
    // 打印自动分类
    console.log(auto_cid_array);
    let auto_cid = auto_cid_array[0][1] > 0.7 ||cid == default_cid ? auto_cid_array[0][0] :cid;
    if (_.v.isIn(auto_cid,C.threadCategory.SPAM_thread_array)) { //是否广告类中
        ret.cid = auto_cid;
        ret.cid_display = cid == -1 ? default_cid : cid;
        ret.SPAM = 1;
    } else if (auto_cid == cid) { // 如自动分类同用户分类
        ret.cid = cid;
        ret.cid_display = cid;
    } else {
        ret.cid = auto_cid;
        ret.cid_display = auto_cid;
    }
    if(data.cid==ret.cid){//分类方式，0为用户分类，1人工分类，2机器分类
        ret.ctype=0;
    }else{
        ret.ctype=2;
    }
    return ret;
};


/**
 * 查询相关的其他帖子,推荐10条
 * @param obj  包含act,tid,replies,imgcount,views,post等参数，act=1,务必传tid,act=2，务必传post
 * 返回数组[{uid:xx,tid:xx},{uid:xx,tid:xx}...]
 */
exports.recommendThread = function*(obj){
    let fields = obj;
    let act = parseInt(fields.act);
    let tid = parseInt(fields.tid);
    let post = fields.post;
    if(!_.v.isIn(act,[1,2])){
        return [];
    }
    let body ={};
    let res=[];
    //默认值参数
    var default_value_replies = 0;
    var default_value_disableVest = 0; // 0 or 1
    var default_value_imgcount = 1; // 0 or 1
    var default_value_view = 1; // 0 or 1

    let replies = fields.replies ? parseInt(fields.replies) : default_value_replies;
    let disableVest = (fields.disableVest==1) ? 1 : default_value_disableVest;
    let imgcount = fields.imgcount ? parseInt(fields.imgcount) : default_value_imgcount;
    let views = fields.views ?parseInt(fields.views) : default_value_view;
    if(act==1){
        if(!tid){
            return [];
        }
        //取redis缓存拿数据，没有去es服务器拿数据
        var key = C.redisPre.thread_similar;
        key = _s.sprintf(key,tid);
        var temp = yield this.redisCo.EXISTS(key);
        if(temp==1){
            //读缓存内容
            console.log('get data from redis:');
            let tmpArr = yield this.redisCo.LRANGE(key, 0, -1);
            for(let i in tmpArr){
                res.push(JSON.parse(tmpArr[i]));
            }
        }else{
            //验证帖子有效性
            let threadInfo = yield this.returnThreadInfo(tid);
            if(_.isEmpty(threadInfo[0])){
                return [];
            }
            body =_.extend(body,{act:act,tid:tid,replies:replies,disableVest:disableVest,imgcount:imgcount,views:views});
            res = yield o2oServiceApi.post('article','similar2',1,body);
            //写入缓存，缓存内容，缓存时间
            console.log(res);
            if(res.status==400||res.length==0){
                return [];
            }
            var arr = [];
            arr.push(key);
            for (var i in res) {
                arr.push(JSON.stringify({uid:res[i]['uid'],tid:res[i]['tid']}));
            }
            yield this.redisCo.RPUSH(arr);
            yield this.redisCo.expire(key, C.redisPre.thread_similar_ttl);
            console.log('get data from es:');
        }
    }else{
        if(!post){
            return [];
        }
        body =_.extend(body,{act:act,post:post,replies:replies,disableVest:disableVest,imgcount:imgcount,views:views});
        res = yield o2oServiceApi.post('article','similar2',1,body);
        if(res.status==400||res.length==0){
            return [];
        }
    }
    return res;
}

/**
 * 以今天0点为基点返回一周前的时间戳秒数
 * @returns {number}
 */
exports.getzeroSeconds =function(){
        var now = new Date();
        var year =now.getFullYear();
        var month =now.getMonth()+1;
        var date = now.getDate();
        var timestr =year+'-'+month+'-'+date+" 0:0:0";
        var zerodate =new Date(timestr);//获取今天0点的毫秒时间戳
        //console.log(zerodate);
        return  (zerodate.valueOf()-604800000)/1000;
}


/**
 * 对o2o服务中的category进行基本操作，包括添加分类，获取分类列表，更新分类等
 * @param body
 * @param action
 * @returns {*}
 */
exports.geto2oCategoryList =function*(body,action){
    if(!_.v.isIn(action,['add','update','list'])){action='list'}
    var res = _.isObject(body) && !_.isEmpty(body) ? yield o2oServiceApi.post('category',action,1,body) : {};
    return res;
};
/**
 * 获取用户第三方账号绑定状态
 * @returns {number}
 */
exports.get3rdBindInformation=function*(uid){
    //获取绑定的社会化账号列表
    let userBindList={uid:uid,QQ:0,WX:0,Mobile:0,boundAccount:0};
    let bindList=yield mysql.query('SELECT uid,mediatype from mh_users_token where uid=? and `status`=1',[uid]);

    //判断是否绑定QQ
    let QQ_bind = _.filter(bindList, function (record) {
        return record.mediatype ==1;
    });
    if(QQ_bind.length>0){
        userBindList.QQ=1;
        userBindList.boundAccount=userBindList.boundAccount+1;
    }
    //判断是否绑定微信
    let WX_bind = _.filter(bindList, function (record) {
        return record.mediatype ==4;
    });
    if(WX_bind.length>0){
        userBindList.WX=1;
        userBindList.boundAccount=userBindList.boundAccount+1;
    }
    let userMobile=yield this.userMobile(uid);
    if(userMobile&&userMobile.length>0){
        userMobile.Mobile=1;
        userBindList.boundAccount=userBindList.boundAccount+1;
    }
    return userBindList;
};

/*
 @todo 查询用户抽奖活动状态查询
 @return  retcode
 act==4(是否可抽奖)
 1.抽奖活动没开始；
 2.兑奖活动已结束；
 3.需要登录后操作；
 4.今天已经抽过奖了；
 5.你已经兑过奖了；
 6.可抽奖。


 act==5(是否可兑奖)
 是否可兑奖：
 1.兑奖活动未开始；
 2.兑奖活动已结束；
 3.需要登陆后操作；
 4.请先抽奖；
 5.你已兑换过奖品；
 6.可兑奖。
 */
exports.get_userGitActivityState = function*(Env) {
    let fields = Env.I;
    let loginStatus = fields.loginStatus;
    let uid = loginStatus.uid;
    let actid = 3;//抽奖兑换礼品活动
    let activity = yield this.getActivity(actid);
    let activityEntity = new mActivity.marketActivity(activity);
    let act=fields.act;
    let result = {};
    if (activityEntity.actInfo) {
        result.imgurl = C.upyun.activity_img_url + activityEntity.actInfo['imageurl'];
        result.shareurl = C.upyun.activity_img_url + activityEntity.actInfo['shareurl'];
        result.title = activityEntity.actInfo['acttitle'];
        result.actid = activityEntity.actInfo['actid'];
        result.acttype = activityEntity.actInfo['acttype'];
        result.begintime = activityEntity.actInfo['begintime'];
        result.endtime = activityEntity.actInfo['endtime'];
        result.validbegintime = activityEntity.actInfo['validbegintime'];
        result.validendtime = activityEntity.actInfo['validendtime'];
        result.detail = _.str.unescapeHTML(activityEntity.actInfo['detail']);
    }
    let currentDate = this.timestamp();

    if(act==4){//获取是否可抽奖状态
        //抽奖时间未开始
        if (currentDate < result.begintime) {
            result.retcode = 1;
            result.retmsg = "抽奖活动即将开始";
            return result;
        }
        //抽奖时间已结束
        if (currentDate > result.endtime) {
            result.retcode = 2;
            result.retmsg = "抽奖活动已经结束";
            return result;
        }

        //判断是否登录
        if (!loginStatus.status) {
            result.retcode = 3;
            result.retmsg="请先登录后再操作";
            return result;
        }
        let date_now = new Date(new Date().format('yyyy-MM-dd'));
        let date_now_str = date_now.getFullYear() + "-" + (date_now.getMonth() + 1) + "-" + date_now.getDate();
        let has_random_git_today = yield mysql.query('SELECT 1 from mh_user_git_history where uid=? and date=?', [loginStatus.uid, date_now_str]);
        if (has_random_git_today && has_random_git_today.length > 0) {
            result.retcode = 4;
            result.retmsg="你今天已经抽过奖了";
            return result;
        }
        //判断是否已领奖
        let has_receive_git_data = yield mysql.query('SELECT 1 FROM mh_user_git_history mugh INNER JOIN mh_order_captcha moc on mugh.ugh_id=moc.orderid where mugh.uid=? and moc.receive=1', [loginStatus.uid]);
        if (has_receive_git_data && has_receive_git_data.length > 0) {
            result.retcode = 5;
            result.retmsg = "你已经兑过奖了，请留意下一期活动";
            return result;
        }
        else {
            result.retcode = 6;
            result.retmsg = "可抽奖";
            return result;
        }
    }else if(act==5){//获取用户兑奖状态
        //兑奖时间未开始
        if (currentDate < result.validbegintime) {
            result.retcode = 1;
            result.retmsg = "兑奖活动即将开始";
            return result;
        }
        //兑奖时间已结束
        if (currentDate > result.validendtime) {
            result.retcode = 2;
            result.retmsg = "兑奖活动已经结束";
            return result;
        }
        //判断是否登录
        if (!loginStatus.status) {
            result.retcode = 3;
            result.retmsg="请先登录后再操作";
            return result;
        }
        let userActicityData = yield mysql.query('SELECT mugh.uid,moc.receive FROM mh_user_git_history mugh LEFT JOIN mh_order_captcha moc on mugh.ugh_id=moc.orderid where mugh.uid=? ORDER BY moc.receive DESC', [uid]);
        if (userActicityData.length > 0) {//有抽奖记录
            result.captcha=10000+loginStatus.uid;
            if (userActicityData[0].receive == 1) {//已经兑换过奖品
                result.retcode = 5;//已兑换奖品
                result.retmsg="已兑换过奖品";
            }else{
                result.retcode = 6;//可兑奖
                result.retmsg="可兑奖";
            }
            return result;
        }else{//无抽奖记录
            result.retcode = 4;
            result.retmsg="请先抽奖";
            return result;
        }
    }
};


exports.getHotInformation=function *(obj_config){
    var returnData = {
        items: []
    };
    if (((obj_config.act == 7 && obj_config.code < obj_config.latest_code) || (obj_config.act == 20 && obj_config.code>=obj_config.latest_code)) && obj_config.page == 1) { //推荐页增加轮播数据
        //取轮播
        var retData = yield this.getSliderNew({title: '', stid: 14, app_ver_arr: obj_config.fields_app_ver_arr});
        if (!_.isEmpty(retData)) {
            returnData.items.push(retData);
        }
    }
    //推荐页面顶端添加送面膜活动 page=1时
    /*
    if (obj_config.env != 'production') {
        if (((obj_config.act == 7 && obj_config.code < obj_config.latest_code) || obj_config.act == 20) && obj_config.page == 1) {

            //2 推荐页主菜单
            if (obj_config.code > 26) {
                returnData.items.push({
                      type: 9,
                      imgUrl: C.upyun.img_url + '/activity/banner_1.jpg',
                      actid: 1,
                      acttype: 1, // 到屈臣氏店面领取
                      android_height: 63,
                      ios_height: 56
                  }
                );
            }
            // 推送o2o入口
            if (obj_config.code > 29) {
                returnData.items.push({
                      type: 14,
                      imgUrl: C.upyun.img_url + '/activity/o2o.jpg',
                      //actid: 1,
                      //acttype: 1, // o2o入口
                      android_height: 63,
                      ios_height: 56
                  }
                );
            }
        }
    }*/
    if ((obj_config.act == 1 && obj_config.page == 1 && obj_config.menu != 0 && obj_config.version < 3 && obj_config.code<obj_config.latest_code) || (obj_config.act == 7 && obj_config.code < obj_config.latest_code && obj_config.page == 1 && obj_config.menu != 0) || (obj_config.act == 20 && obj_config.code>=obj_config.latest_code)) {
        returnData.items = yield this.spots(1, returnData.items, {
            act: obj_config.act,
            page: obj_config.page,
            app_ver_arr: obj_config.env_app_ver_arr
        });
    }

    /*
    //取达人 增时段控制： act=7 推荐页  & 9-12 18-22点
    if (obj_config.env != 'production' && obj_config.manager == 0) {
        if ((obj_config.act == 7 && obj_config.code < obj_config.latest_code) || obj_config.act == 20) {
            //2 推荐页主菜单
            returnData.items = yield this.spots(2, returnData.items, {
                act: obj_config.act,
                page: obj_config.page,
                version: obj_config.version,
                app_ver_arr: obj_config.env_app_ver_arr
            });
        }
    }*/
    return returnData.items;
};

/**
 *  获取主题帖真实用户点赞数
 * @param liketimes  用户全部点赞数
 * @param tid       主题贴id
 * @returns {number}
 */
exports.getUliketimes = function*(liketimes,tid){
    var vestliketimes =yield mysql.queryOne("select count(b.vid) as vestliketimes from (select uid  from mh_likes WHERE tid=? and first=1) as a INNER JOIN mh_vest as b on a.uid =b.uid",[tid]);
    var reallike=parseInt(liketimes)-parseInt(vestliketimes['vestliketimes']);
    var uliketimes = reallike>0?reallike:0;
    return uliketimes;
};


var crypto = require('crypto');
/**
 * 生成token
 * @param uid default guest
 * @param manager default 0
 * @param time default now
 * @returns {string}
 */
function __getToken(uid, manager, time) {
    uid = typeof uid === 'undefined' ? 'guest' : uid;
    manager = typeof manager === 'undefined' ? '1' : manager;
    time = typeof time === 'undefined' ? new Date().getTime() : time;

    var md5SrcPtn = '_AA_uid=%uid&manager=%manager&time=%time_BB_';
    var tokenSrcPtn = 'uid=%uid&manager=%manager&time=%time&md5=%md5';
    var md5Src = md5SrcPtn
      .replace('%uid', uid)
      .replace('%manager', manager)
      .replace('%time', time);
    var md5Result = crypto.createHash('md5').update(md5Src).digest('hex');
    var tokenSrc = tokenSrcPtn
      .replace('%uid', uid)
      .replace('%manager', manager)
      .replace('%time', time)
      .replace('%md5', md5Result);
    return encodeURIComponent(tokenSrc);
}

//exports.getToken = function (uid, manager, time) {
//    return __getToken(uid, manager, time);
//};

// getToken2.call(this);
exports.getToken2 = function () {
    var loginStatus = this.I.loginStatus;
    var uid = !loginStatus.status ? 'guest' : loginStatus.uid + '';
    //console.log('getToken2',loginStatus,uid);
    var manager = 0;
    var time = new Date().getTime();
    var token = __getToken(uid, manager, time);
    return token;
};


exports.promiseRequest = function (opt) {
    return new Promise(function (fulfil, reject) {
        async_request(opt, function (err, res, body) {
            fulfil({error: err, res: res, body: body});
        });
    });
};

//object array convert to code array
exports.array_2_codeArray= function *(obj_array,key){
    let string_code_arr = [];
    for (let obj of obj_array) {
        string_code_arr.push(obj[key]);
    }
    return string_code_arr;
};